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:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
commitbdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch)
treed00eb50b749cb001e2b08272c91791e66740b05d /source/blender/render
parent78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff)
parent7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff)
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416 Issues: * GHOST/X11 had conflicting changes. Some code was added in 2.5, which was later added in trunk also, but reverted partially, specifically revision 16683. I have left out this reversion in the 2.5 branch since I think it is needed there. http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683 * Scons had various conflicting changes, I decided to go with trunk version for everything except priorities and some library renaming. * In creator.c, there were various fixes and fixes for fixes related to the -w -W and -p options. In 2.5 -w and -W is not coded yet, and -p is done differently. Since this is changed so much, and I don't think those fixes would be needed in 2.5, I've left them out. * Also in creator.c: there was code for a python bugfix where the screen was not initialized when running with -P. The code that initializes the screen there I had to disable, that can't work in 2.5 anymore but left it commented as a reminder. Further I had to disable some new function calls. using src/ and python/, as was done already in this branch, disabled function calls: * bpath.c: error reporting * BME_conversions.c: editmesh conversion functions. * SHD_dynamic: disabled almost completely, there is no python/. * KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled. * text.c: clipboard copy call. * object.c: OB_SUPPORT_MATERIAL. * DerivedMesh.c and subsurf_ccg, stipple_quarttone. Still to be done: * Go over files and functions that were moved to a different location but could still use changes that were done in trunk.
Diffstat (limited to 'source/blender/render')
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/SConscript22
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h31
-rw-r--r--source/blender/render/extern/include/RE_raytrace.h4
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h10
-rw-r--r--source/blender/render/intern/include/occlusion.h49
-rw-r--r--source/blender/render/intern/include/pixelblending.h2
-rw-r--r--source/blender/render/intern/include/pixelshading.h5
-rw-r--r--source/blender/render/intern/include/render_types.h89
-rw-r--r--source/blender/render/intern/include/rendercore.h14
-rw-r--r--source/blender/render/intern/include/renderdatabase.h12
-rw-r--r--source/blender/render/intern/include/shadbuf.h2
-rw-r--r--source/blender/render/intern/include/shading.h10
-rw-r--r--source/blender/render/intern/include/sss.h2
-rw-r--r--source/blender/render/intern/include/strand.h19
-rw-r--r--source/blender/render/intern/include/sunsky.h144
-rw-r--r--source/blender/render/intern/include/texture.h2
-rw-r--r--source/blender/render/intern/include/zbuf.h24
-rw-r--r--source/blender/render/intern/source/convertblender.c1527
-rw-r--r--source/blender/render/intern/source/envmap.c39
-rw-r--r--source/blender/render/intern/source/imagetexture.c40
-rw-r--r--source/blender/render/intern/source/initrender.c26
-rw-r--r--source/blender/render/intern/source/occlusion.c1763
-rw-r--r--source/blender/render/intern/source/pipeline.c636
-rw-r--r--source/blender/render/intern/source/pixelblending.c125
-rw-r--r--source/blender/render/intern/source/pixelshading.c154
-rw-r--r--source/blender/render/intern/source/rayshade.c316
-rw-r--r--source/blender/render/intern/source/raytrace.c35
-rw-r--r--source/blender/render/intern/source/rendercore.c1103
-rw-r--r--source/blender/render/intern/source/renderdatabase.c198
-rw-r--r--source/blender/render/intern/source/shadbuf.c61
-rw-r--r--source/blender/render/intern/source/shadeinput.c323
-rw-r--r--source/blender/render/intern/source/shadeoutput.c185
-rw-r--r--source/blender/render/intern/source/sss.c41
-rw-r--r--source/blender/render/intern/source/strand.c1186
-rw-r--r--source/blender/render/intern/source/sunsky.c499
-rw-r--r--source/blender/render/intern/source/texture.c200
-rw-r--r--source/blender/render/intern/source/zbuf.c1180
38 files changed, 7498 insertions, 2582 deletions
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index b543dff49ff..0b659554d1a 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -29,7 +29,7 @@ FILE(GLOB SRC intern/source/*.c)
SET(INC
intern/include ../../../intern/guardedalloc ../blenlib ../makesdna
extern/include ../blenkernel ../radiosity/extern/include ../imbuf
- ../quicktime ../include ../../kernel/gen_messaging ../yafray
+ ../quicktime ../include ../../kernel/gen_messaging ../yafray ../blenloader
)
IF(WITH_OPENEXR)
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index d06331a5b48..7f799a78834 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -6,26 +6,26 @@ sources = env.Glob('intern/source/*.c')
incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna'
incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
-incs += ' ../quicktime ../editors/include ../../kernel/gen_messaging'
+incs += ' ../include ../blenloader'
defs = []
-if env['WITH_BF_YAFRAY'] == 1:
- incs += ' ../yafray'
+if env['WITH_BF_YAFRAY']:
+ incs += ' ../yafray'
else:
- defs.append('DISABLE_YAFRAY')
+ defs.append('DISABLE_YAFRAY')
-if env['WITH_BF_QUICKTIME'] == 1:
- defs.append('WITH_QUICKTIME')
- incs += ' ' + env['BF_QUICKTIME_INC']
+if env['WITH_BF_QUICKTIME']:
+ defs.append('WITH_QUICKTIME')
+ incs += ' ../quicktime ' + env['BF_QUICKTIME_INC']
-if env['WITH_BF_FFMPEG'] == 1:
- defs.append('WITH_FFMPEG')
+if env['WITH_BF_FFMPEG']:
+ defs.append('WITH_FFMPEG')
if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
+ defs.append('WITH_OPENEXR')
if env['OURPLATFORM']=='linux2':
- cflags='-pthread'
+ cflags='-pthread'
env.BlenderLib ( libname = 'bf_render', sources = sources, includes = Split(incs), defines=defs, libtype='core', priority=55, compileflags=cflags )
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index d202ea1eed5..60557403143 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -38,6 +38,7 @@ struct Scene;
struct RenderData;
struct NodeBlurData;
struct Object;
+struct bNodeTree;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is what is exposed of render to outside world */
@@ -73,7 +74,7 @@ typedef struct RenderLayer {
/* copy of RenderData */
char name[RE_MAXNAME];
- unsigned int lay;
+ unsigned int lay, lay_zmask;
int layflag, passflag, pass_xor;
struct Material *mat_override;
@@ -88,10 +89,11 @@ typedef struct RenderLayer {
} RenderLayer;
typedef struct RenderResult {
+ struct RenderResult *next, *prev;
/* target image size */
int rectx, recty;
- short crop, pad;
+ short crop, sample_nr;
/* optional, 32 bits version of picture, used for ogl render and image curves */
int *rect32;
@@ -113,7 +115,6 @@ typedef struct RenderResult {
volatile RenderLayer *renlay;
/* optional saved endresult on disk */
- char exrfile[FILE_MAXDIR];
void *exrhandle;
/* for render results in Image, verify validity for sequences */
@@ -121,6 +122,7 @@ typedef struct RenderResult {
} RenderResult;
+
typedef struct RenderStats {
int totface, totvert, totstrand, tothalo, totlamp, totpart;
short curfield, curblur, curpart, partsdone, convertdone;
@@ -151,7 +153,7 @@ struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name)
float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype);
/* obligatory initialize call, disprect is optional */
-void RE_InitState (struct Render *re, struct RenderData *rd, int winx, int winy, rcti *disprect);
+void RE_InitState (struct Render *re, struct Render *source, struct RenderData *rd, int winx, int winy, rcti *disprect);
/* use this to change disprect of active render */
void RE_SetDispRect (struct Render *re, rcti *disprect);
@@ -175,17 +177,23 @@ void RE_DataBase_ApplyWindow(struct Render *re);
/* override the scene setting for amount threads, commandline */
void RE_set_max_threads(int threads);
+/* set the render threads based on the commandline and autothreads setting */
+void RE_init_threadcount(Render *re);
+
/* the main processor, assumes all was set OK! */
void RE_TileProcessor(struct Render *re, int firsttile, int threaded);
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Scene *scene, int frame);
-void RE_BlenderAnim(struct Render *re, struct Scene *scene, int sfra, int efra);
+void RE_BlenderAnim(struct Render *re, struct Scene *scene, int sfra, int efra, int tfra);
void RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
void RE_WriteRenderResult(RenderResult *rr, char *filename, int compress);
struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty);
+/* do a full sample buffer compo */
+void RE_MergeFullSample(struct Render *re, struct Scene *sce, struct bNodeTree *ntree);
+
/* ancient stars function... go away! */
void RE_make_stars(struct Render *re, void (*initfunc)(void),
void (*vertexfunc)(float*), void (*termfunc)(void));
@@ -206,11 +214,14 @@ float RE_filter_value(int type, float x);
void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
/* shaded view or baking options */
-#define RE_BAKE_LIGHT 0
-#define RE_BAKE_ALL 1
-#define RE_BAKE_AO 2
-#define RE_BAKE_NORMALS 3
-#define RE_BAKE_TEXTURE 4
+#define RE_BAKE_LIGHT 0
+#define RE_BAKE_ALL 1
+#define RE_BAKE_AO 2
+#define RE_BAKE_NORMALS 3
+#define RE_BAKE_TEXTURE 4
+#define RE_BAKE_DISPLACEMENT 5
+#define RE_BAKE_SHADOW 6
+
void RE_Database_Baking(struct Render *re, struct Scene *scene, int type, struct Object *actob);
void RE_DataBase_GetView(struct Render *re, float mat[][4]);
diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h
index 39bf2be4256..8f429f7dd90 100644
--- a/source/blender/render/extern/include/RE_raytrace.h
+++ b/source/blender/render/extern/include/RE_raytrace.h
@@ -70,7 +70,7 @@ typedef struct Isect {
int ob_last;
short isect; /* which half of quad */
- short mode; /* RE_RAYSHADOW, RE_RAYMIRROR, RE_RAYSHADOW_TRA */
+ short mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
int lay; /* -1 default, set for layer lamps */
/* only used externally */
@@ -89,7 +89,7 @@ typedef struct Isect {
/* function callbacks for face type abstraction */
typedef void (*RayCoordsFunc)(RayFace *face,
float **v1, float **v2, float **v3, float **v4);
-typedef int (*RayCheckFunc)(Isect *is, RayFace *face);
+typedef int (*RayCheckFunc)(Isect *is, int ob, RayFace *face);
typedef float *(*RayObjectTransformFunc)(void *userdata, int ob);
/* tree building and freeing */
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 5b81052f5d2..888474ffa18 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -47,7 +47,7 @@ typedef struct ShadeResult
{
float combined[4];
float col[4];
- float alpha;
+ float alpha, mist, z;
float diff[3]; /* no ramps, shadow, etc */
float spec[3];
float shad[3];
@@ -64,6 +64,7 @@ struct ShadeInputCopy {
struct Material *mat;
struct VlakRen *vlr;
+ struct StrandRen *strand;
struct ObjectInstanceRen *obi;
struct ObjectRen *obr;
int facenr;
@@ -96,6 +97,7 @@ typedef struct ShadeInput
struct Material *mat;
struct VlakRen *vlr;
+ struct StrandRen *strand;
struct ObjectInstanceRen *obi;
struct ObjectRen *obr;
int facenr;
@@ -132,7 +134,8 @@ typedef struct ShadeInput
/* texture coordinates */
float lo[3], gl[3], ref[3], orn[3], winco[3], sticky[3], vcol[4], rad[3];
float refcol[4], displace[3];
- float strand, tang[3], stress, winspeed[4];
+ float strandco, tang[3], nmaptang[3], stress, winspeed[4];
+ float duplilo[3], dupliuv[3];
ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */
ShadeInputCol col[8]; /* 8 = MAX_MCOL */
@@ -154,6 +157,8 @@ typedef struct ShadeInput
int xs, ys; /* pixel to be rendered */
int mask; /* subsample mask */
+ float scanco[3]; /* original scanline coordinate without jitter */
+
int samplenr; /* sample counter, to detect if we should do shadow again */
int depth; /* 1 or larger on raytrace shading */
@@ -166,6 +171,7 @@ typedef struct ShadeInput
/* from initialize, part or renderlayer */
short do_preview; /* for nodes, in previewrender */
short thread, sample; /* sample: ShadeSample array index */
+
unsigned int lay;
int layflag, passflag, combinedflag;
struct Group *light_override;
diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/render/intern/include/occlusion.h
new file mode 100644
index 00000000000..646ad30b318
--- /dev/null
+++ b/source/blender/render/intern/include/occlusion.h
@@ -0,0 +1,49 @@
+/*
+ * $Id$
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 *****
+ */
+
+#ifndef OCCLUSION_H
+#define OCCLUSION_H
+
+struct Render;
+struct ShadeInput;
+struct ShadeResult;
+struct RenderPart;
+struct ShadeSample;
+struct DerivedMesh;
+struct ObjectRen;
+
+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
index 04c5a3977a3..f7f4bc76eae 100644
--- a/source/blender/render/intern/include/pixelblending.h
+++ b/source/blender/render/intern/include/pixelblending.h
@@ -35,6 +35,8 @@
*/
void add_filt_fmask(unsigned int mask, float *col, 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], float *col, float *rowbuf, int row_w, int col_h, int x, int y);
+void mask_array(unsigned int mask, float filt[][3]);
/**
* Alpha-over blending for floats.
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
index d2235784a59..c6b11b4af9a 100644
--- a/source/blender/render/intern/include/pixelshading.h
+++ b/source/blender/render/intern/include/pixelshading.h
@@ -45,7 +45,7 @@
* mask is pixel coverage in bits
* @return pointer to the object
*/
-void shadeHaloFloat(HaloRen *har,
+int shadeHaloFloat(HaloRen *har,
float *col, int zz,
float dist, float xn,
float yn, short flarec);
@@ -55,7 +55,8 @@ void shadeHaloFloat(HaloRen *har,
*/
void shadeSkyPixel(float *collector, float fx, float fy);
void shadeSkyView(float *colf, float *rco, float *view, float *dxyview);
-
+void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance);
+void shadeSunView(float *colf, float *view);
/* ------------------------------------------------------------------------- */
#endif
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 7fbbd0f5abc..1768b052b54 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -42,6 +42,9 @@
#include "RE_pipeline.h"
#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */
+#include "sunsky.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
struct Object;
struct MemArena;
@@ -64,8 +67,10 @@ typedef struct SampleTables
typedef struct QMCSampler
{
+ struct QMCSampler *next, *prev;
int type;
int tot;
+ int used;
double *samp2d;
double offs[BLENDER_MAX_THREADS][2];
} QMCSampler;
@@ -79,17 +84,18 @@ typedef struct RenderPart
{
struct RenderPart *next, *prev;
- /* result of part rendering */
- RenderResult *result;
+ 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 */
- long *rectdaps; /* delta acum buffer for pixel structs */
+ 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 */
- long *rectall; /* buffer for all faces for sss */
+ intptr_t *rectall; /* buffer for all faces for sss */
rcti disprect; /* part coordinates within total picture */
int rectx, recty; /* the size */
@@ -113,6 +119,8 @@ struct Render
RenderResult *result;
/* if render with single-layer option, other rendered layers are stored here */
RenderResult *pushedresult;
+ /* a list of RenderResults, for fullsample */
+ ListBase fullresult;
/* window size, display rect, viewplane */
int winx, winy;
@@ -147,7 +155,10 @@ struct Render
/* samples */
SampleTables *samples;
float jit[32][2];
- QMCSampler *qsa;
+ ListBase *qmcsamplers;
+
+ /* shadow counter, detect shadow-reuse for shaders */
+ int shadowsamplenr[BLENDER_MAX_THREADS];
/* scene, and its full copy of renderdata and world */
Scene *scene;
@@ -158,6 +169,10 @@ struct Render
/* octree tables and variables for raytrace */
void *raytree;
+
+ /* occlusion tree */
+ void *occlusiontree;
+ ListBase strandsurface;
/* use this instead of R.r.cfra */
float cfra;
@@ -170,11 +185,9 @@ struct Render
ListBase lampren; /* storage, for free */
ListBase objecttable;
- struct RenderBuckets *strandbuckets;
struct ObjectInstanceRen *objectinstance;
ListBase instancetable;
- struct GHash *objecthash;
int totinstance;
struct Image *backbuf, *bakebuf;
@@ -215,7 +228,7 @@ struct ISBData;
typedef struct ShadSampleBuf {
struct ShadSampleBuf *next, *prev;
- long *zbuf;
+ intptr_t *zbuf;
char *cbuf;
} ShadSampleBuf;
@@ -241,7 +254,9 @@ typedef struct ObjectRen {
struct ObjectRen *next, *prev;
struct Object *ob, *par;
struct Scene *sce;
- int index, psysindex;
+ int index, psysindex, flag, lay;
+
+ float boundbox[2][3];
int totvert, totvlak, totstrand, tothalo;
int vertnodeslen, vlaknodeslen, strandnodeslen, blohalen;
@@ -249,11 +264,13 @@ typedef struct ObjectRen {
struct VlakTableNode *vlaknodes;
struct StrandTableNode *strandnodes;
struct HaloRen **bloha;
- ListBase strandbufs;
+ struct StrandBuffer *strandbuf;
char (*mtface)[32];
char (*mcol)[32];
- int actmtface, actmcol;
+ int actmtface, actmcol, bakemtface;
+
+ float obmat[4][4]; /* only used in convertblender.c, for instancing */
} ObjectRen;
typedef struct ObjectInstanceRen {
@@ -261,11 +278,14 @@ typedef struct ObjectInstanceRen {
ObjectRen *obr;
Object *ob, *par;
- int index, psysindex;
+ int index, psysindex, lay;
- float mat[4][4], imat[3][3];
+ float mat[4][4], nmat[3][3]; /* nmat is inverse mat tranposed */
short flag;
+ float dupliorco[3], dupliuv[2];
+ float (*duplitexmat)[4];
+
float *vectors;
int totvector;
} ObjectInstanceRen;
@@ -302,13 +322,10 @@ typedef struct RadFace {
typedef struct VlakRen {
struct VertRen *v1, *v2, *v3, *v4; /* keep in order for ** addressing */
- unsigned int lay;
float n[3];
struct Material *mat;
char puno;
char flag, ec;
- RadFace *radface;
- ObjectRen *obr;
int index;
} VlakRen;
@@ -328,22 +345,43 @@ typedef struct HaloRen
struct Material *mat;
} 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 (*col)[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;
- int totvert;
+ 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;
+ float adaptcos, minwidth, widthfade;
float winmat[4][4];
int winx, winy;
@@ -380,8 +418,10 @@ typedef struct LampRen {
float xs, ys, dist;
float co[3];
- short type, mode;
+ short type;
+ int mode;
float r, g, b, k;
+ float shdwr, shdwg, shdwb;
float energy, haint;
int lay;
float spotsi,spotbl;
@@ -420,9 +460,11 @@ typedef struct LampRen {
float area_size, area_sizey, area_sizez;
float adapt_thresh;
+ /* sun/sky */
+ struct SunSky *sunsky;
+
struct ShadBuf *shb;
float *jitter;
- QMCSampler *qsa;
float imat[3][3];
float spottexfac;
@@ -463,6 +505,9 @@ typedef struct LampRen {
#define R_LAMPHALO 8
#define R_GLOB_NOPUNOFLIP 16
#define R_NEED_TANGENT 32
+#define R_SKIP_MULTIRES 64
+#define R_BAKE_TRACE 128
+#define R_BAKING 256
/* vlakren->flag (vlak = face in dutch) char!!! */
#define R_SMOOTH 1
@@ -481,10 +526,14 @@ typedef struct LampRen {
#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_NEED_VECTORS 4
#endif /* RENDER_TYPES_H */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index ab009a980a5..4b28529a147 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -37,8 +37,8 @@
/* vector defines */
-#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]
-#define VECMUL(dest, f) dest[0]*= f; dest[1]*= f; dest[2]*= f
+#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]; }
+#define VECMUL(dest, f) { dest[0]*= f; dest[1]*= f; dest[2]*= f; }
struct HaloRen;
struct ShadeInput;
@@ -47,13 +47,14 @@ struct World;
struct RenderPart;
struct RenderLayer;
struct ObjectRen;
+struct ListBase;
/* ------------------------------------------------------------------------- */
typedef struct PixStr
{
struct PixStr *next;
- int obi, facenr, z;
+ int obi, facenr, z, maskz;
unsigned short mask;
short shadfac;
} PixStr;
@@ -87,6 +88,9 @@ 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);
+
+
/* -------- ray.c ------- */
extern void freeraytree(Render *re);
@@ -97,9 +101,7 @@ extern void ray_trace(ShadeInput *, ShadeResult *);
extern void ray_ao(ShadeInput *, float *);
extern void init_jitter_plane(LampRen *lar);
extern void init_ao_sphere(struct World *wrld);
-extern void init_lamp_hammersley(LampRen *lar);
-extern void free_lamp_qmcsampler(LampRen *lar);
-extern void init_render_hammersley(Render *re);
+extern void init_render_qmcsampler(Render *re);
extern void free_render_qmcsampler(Render *re);
#endif /* RENDER_EXT_H */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index c919a54008e..dc28eae1cc2 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -42,6 +42,7 @@ struct CustomData;
struct StrandBuffer;
struct StrandRen;
struct ObjectInstanceRen;
+struct RadFace;
#define RE_QUAD_MASK 0x7FFFFFF
#define RE_QUAD_OFFS 0x8000000
@@ -63,6 +64,8 @@ typedef struct VlakTableNode {
struct MCol *mcol;
int totmtface, totmcol;
float *surfnor;
+ float *tangent;
+ struct RadFace **radface;
} VlakTableNode;
typedef struct StrandTableNode {
@@ -70,6 +73,7 @@ typedef struct StrandTableNode {
float *winspeed;
float *surfnor;
float *simplify;
+ int *face;
struct MCol *mcol;
float *uv;
int totuv, totmcol;
@@ -82,6 +86,7 @@ void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
void set_normalflags(struct Render *re, struct ObjectRen *obr);
void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs, int do_buckets);
+int clip_render_object(float boundbox[][3], float *bounds, float mat[][4]);
/* functions are not exported... so wrong names */
@@ -93,8 +98,8 @@ struct HaloRen *RE_inithalo(struct Render *re, struct ObjectRen *obr, struct Mat
struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, struct Material *ma, float *vec, float *vec1, float *orco, float *uvco, float hasize, float vectsize, int seed);
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);
-void RE_addRenderInstance(struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, int index, int psysindex, float mat[][4]);
+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], int lay);
void RE_makeRenderInstances(struct Render *re);
void RE_instanceTransformNormal(struct ObjectInstanceRen *obi, float *nor, float *tnor);
@@ -108,12 +113,15 @@ float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ve
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);
float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
+float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify);
+RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
int 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);
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
index a96baab8294..7015b4bc1bf 100644
--- a/source/blender/render/intern/include/shadbuf.h
+++ b/source/blender/render/intern/include/shadbuf.h
@@ -54,7 +54,7 @@ void threaded_makeshadowbufs(struct Render *re);
* @param inp The inproduct between viewvector and ?
*
*/
-float testshadowbuf(struct ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp);
+float testshadowbuf(struct Render *re, struct ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp, float mat_bias);
/**
* Determines the shadow factor for lamp <lar>, between <p1>
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 6ca63a2976d..54311d2515a 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -40,13 +40,13 @@ struct ObjectInstanceRen obi;
/* 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 */
+ 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];
-
- int samplenr; /* counter, detect shadow-reuse for shaders */
} ShadeSample;
@@ -56,7 +56,8 @@ 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, volatile int obi, volatile int facenr, int normal_flip);
void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
-void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z);
+void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float *view, float *dxyview, float *co, float *dxco, float *dyco);
+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_flip_normals(struct ShadeInput *shi);
@@ -69,6 +70,7 @@ void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struc
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);
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
index 660fb544227..9ffdcaf206a 100644
--- a/source/blender/render/intern/include/sss.h
+++ b/source/blender/render/intern/include/sss.h
@@ -59,7 +59,7 @@ void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area,
void free_sss(struct Render *re);
int sample_sss(struct Render *re, struct Material *mat, float *co, float *col);
-int has_sss_tree(struct Render *re, struct Material *mat);
+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
index c6ec72125ad..09988125830 100644
--- a/source/blender/render/intern/include/strand.h
+++ b/source/blender/render/intern/include/strand.h
@@ -41,6 +41,9 @@ struct RenderBuckets;
struct RenderPrimitiveIterator;
struct ZSpan;
struct ObjectInstanceRen;
+struct StrandSurface;
+struct DerivedMesh;
+struct ObjectRen;
typedef struct StrandPoint {
/* position within segment */
@@ -61,6 +64,7 @@ typedef struct StrandPoint {
float co1[3], co2[3];
float hoco1[4], hoco2[4];
float zco1[3], zco2[3];
+ int clip1, clip2;
/* screen space */
float hoco[4];
@@ -81,9 +85,20 @@ typedef struct StrandSegment {
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], struct StrandPart *spart, struct ZSpan *zspan, StrandSegment *sseg);
-void project_strands(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int do_buckets);
+void render_strand_segment(struct Render *re, float winmat[][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg);
+void strand_minmax(struct StrandRen *strand, float *min, float *max);
+
+struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[][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 StrandVert *svert);
struct RenderBuckets *init_buckets(struct Render *re);
void add_buckets_primitive(struct RenderBuckets *buckets, float *min, float *max, void *prim);
diff --git a/source/blender/render/intern/include/sunsky.h b/source/blender/render/intern/include/sunsky.h
new file mode 100644
index 00000000000..f61338bcf27
--- /dev/null
+++ b/source/blender/render/intern/include/sunsky.h
@@ -0,0 +1,144 @@
+ /**
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): zaghaghi
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * 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/
+ * */
+#ifndef SUNSKY_H_
+#define SUNSKY_H_
+
+#define SPECTRUM_MAX_COMPONENTS 100
+#define SPECTRUM_START 350.0
+#define SPECTRUM_END 800.0
+
+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
+ * http://projects.blender.org/tracker/?func=detail&atid=127&aid=8063&group_id=9*/
+ 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;
+
+/**
+ * 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 informtion 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, float *toSun, float horizon_brightness,
+ float spread,float sun_brightness, float sun_size, float back_scatter,
+ float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace);
+
+/**
+ * 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]);
+
+/**
+ * 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]);
+
+/**
+ * InitAtmosphere:
+ * this function intiate 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, multiplyed 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);
+
+/**
+ * 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]);
+
+/**
+ * ClipColor:
+ * clip a color to range [0,1];
+ * */
+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 8e56c4a852f..be5471e07c4 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -55,7 +55,7 @@ struct ImBuf;
void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf);
void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag);
void do_material_tex(struct ShadeInput *shi);
-void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf);
+void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf, int effect);
void init_render_textures(Render *re);
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index 4d30c1e0dfb..b6d0c656f63 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -36,6 +36,8 @@ struct LampRen;
struct VlakRen;
struct ListBase;
struct ZSpan;
+struct APixstrand;
+struct StrandShadeCache;
void fillrect(int *rect, int x, int y, int val);
@@ -48,12 +50,11 @@ void projectverto(float *v1, float winmat[][4], float *adr);
int testclip(float *v);
void zbuffer_shadow(struct Render *re, float winmat[][4], struct LampRen *lar, int *rectz, int size, float jitx, float jity);
-void zbuffer_solid(struct RenderPart *pa, unsigned int layer, short layflag, void (*fillfunc)(struct RenderPart*, struct ZSpan*, int, void*), void *data);
+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);
-unsigned short *zbuffer_strands_shade(struct Render *re, struct RenderPart *pa, struct RenderLayer *rl, float *pass);
-void convert_zbuf_to_distbuf(struct RenderPart *pa, struct RenderLayer *rl);
+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 RenderLayer *rl, struct APixstrand *apixbuf, struct ListBase *apsmbase, struct StrandShadeCache *cache);
typedef struct APixstr {
unsigned short mask[4]; /* jitter mask */
@@ -64,10 +65,20 @@ typedef struct APixstr {
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;
- struct APixstr *ps;
+ void *ps;
} APixstrMain;
/* span fill in method, is also used to localize data for zbuffering */
@@ -84,12 +95,15 @@ typedef struct ZSpan {
int *rectz1; /* seconday 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 */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index d8ad518da14..a9bc2131d77 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -54,6 +54,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_object_fluidsim.h"
@@ -99,6 +100,7 @@
#include "envmap.h"
//XXX #include "multires.h"
+#include "occlusion.h"
#include "render_types.h"
#include "rendercore.h"
#include "renderdatabase.h"
@@ -106,9 +108,12 @@
#include "radio.h"
#include "shadbuf.h"
#include "shading.h"
+#include "strand.h"
#include "texture.h"
#include "sss.h"
+#include "strand.h"
#include "zbuf.h"
+#include "sunsky.h"
#ifndef DISABLE_YAFRAY /* disable yafray */
@@ -198,6 +203,7 @@ void RE_make_stars(Render *re, void (*initfunc)(void),
else stargrid *= 1.0; /* then it draws fewer */
if(re) MTC_Mat4Invert(mat, re->viewmat);
+ else MTC_Mat4One(mat);
/* BOUNDING BOX CALCULATION
* bbox goes from z = loc_near_var | loc_far_var,
@@ -228,7 +234,7 @@ void RE_make_stars(Render *re, void (*initfunc)(void),
}
if(re) /* add render object for stars */
- obr= RE_addRenderObject(re, NULL, NULL, 0, 0);
+ obr= RE_addRenderObject(re, NULL, NULL, 0, 0, 0);
for (x = sx, fx = sx * stargrid; x <= ex; x++, fx += stargrid) {
for (y = sy, fy = sy * stargrid; y <= ey ; y++, fy += stargrid) {
@@ -447,34 +453,8 @@ static void calc_edge_stress(Render *re, ObjectRen *obr, Mesh *me)
MEM_freeN(accum);
}
-void tangent_from_uv(float *uv1, float *uv2, float *uv3, float *co1, float *co2, float *co3, float *n, float *tang)
-{
- float tangv[3], ct[3], e1[3], e2[3], s1, t1, s2, t2, det;
-
- s1= uv2[0] - uv1[0];
- s2= uv3[0] - uv1[0];
- t1= uv2[1] - uv1[1];
- t2= uv3[1] - uv1[1];
- det= 1.0f / (s1 * t2 - s2 * t1);
-
- /* normals in render are inversed... */
- VecSubf(e1, co1, co2);
- VecSubf(e2, co1, co3);
- tang[0] = (t2*e1[0] - t1*e2[0])*det;
- tang[1] = (t2*e1[1] - t1*e2[1])*det;
- tang[2] = (t2*e1[2] - t1*e2[2])*det;
- tangv[0] = (s1*e2[0] - s2*e1[0])*det;
- tangv[1] = (s1*e2[1] - s2*e1[1])*det;
- tangv[2] = (s1*e2[2] - s2*e1[2])*det;
- Crossf(ct, tang, tangv);
-
- /* check flip */
- if ((ct[0]*n[0] + ct[1]*n[1] + ct[2]*n[2]) < 0.0f)
- VecMulf(tang, -1.0f);
-}
-
/* gets tangent from tface or orco */
-static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr)
+static void calc_tangent_vector(ObjectRen *obr, VertexTangent **vtangents, MemArena *arena, VlakRen *vlr, int do_nmap_tangent, 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;
@@ -500,30 +480,55 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr)
tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
- tav= RE_vertren_get_tangent(obr, v1, 1);
- VECADD(tav, tav, tang);
- tav= RE_vertren_get_tangent(obr, v2, 1);
- VECADD(tav, tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
- VECADD(tav, tav, tang);
-
- if(v4) {
- tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
-
+ if(do_tangent) {
tav= RE_vertren_get_tangent(obr, v1, 1);
VECADD(tav, tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
+ tav= RE_vertren_get_tangent(obr, v2, 1);
VECADD(tav, tav, tang);
- tav= RE_vertren_get_tangent(obr, v4, 1);
+ tav= RE_vertren_get_tangent(obr, v3, 1);
VECADD(tav, tav, tang);
}
+
+ if(do_nmap_tangent) {
+ sum_or_add_vertex_tangent(arena, &vtangents[v1->index], tang, uv1);
+ sum_or_add_vertex_tangent(arena, &vtangents[v2->index], tang, uv2);
+ sum_or_add_vertex_tangent(arena, &vtangents[v3->index], tang, uv3);
+ }
+
+ if(v4) {
+ tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
+
+ if(do_tangent) {
+ tav= RE_vertren_get_tangent(obr, v1, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(obr, v3, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(obr, v4, 1);
+ VECADD(tav, tav, tang);
+ }
+
+ if(do_nmap_tangent) {
+ sum_or_add_vertex_tangent(arena, &vtangents[v1->index], tang, uv1);
+ sum_or_add_vertex_tangent(arena, &vtangents[v3->index], tang, uv3);
+ sum_or_add_vertex_tangent(arena, &vtangents[v4->index], tang, uv4);
+ }
+ }
}
-static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent)
+static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent, int do_nmap_tangent)
{
+ MemArena *arena= NULL;
+ VertexTangent **vtangents= NULL;
int a;
+ if(do_nmap_tangent) {
+ arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ BLI_memarena_use_calloc(arena);
+
+ vtangents= MEM_callocN(sizeof(VertexTangent*)*obr->totvert, "VertexTangent");
+ }
+
/* clear all vertex normals */
for(a=0; a<obr->totvert; a++) {
VertRen *ver= RE_findOrAddVert(obr, a);
@@ -596,10 +601,10 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent)
v3->n[2] +=fac3*vlr->n[2];
}
- if(do_tangent) {
+ if(do_nmap_tangent || do_tangent) {
/* tangents still need to be calculated for flat faces too */
/* weighting removed, they are not vertexnormals */
- calc_tangent_vector(obr, vlr);
+ calc_tangent_vector(obr, vtangents, arena, vlr, do_nmap_tangent, do_tangent);
}
}
@@ -618,6 +623,30 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent)
if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
}
}
+
+ if(do_nmap_tangent) {
+ VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4;
+ MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
+
+ if(tface) {
+ float *vtang, *ftang= RE_vlakren_get_nmap_tangent(obr, vlr, 1);
+
+ vtang= find_vertex_tangent(vtangents[v1->index], tface->uv[0]);
+ VECCOPY(ftang, vtang);
+ Normalize(ftang);
+ vtang= find_vertex_tangent(vtangents[v2->index], tface->uv[1]);
+ VECCOPY(ftang+3, vtang);
+ Normalize(ftang+3);
+ vtang= find_vertex_tangent(vtangents[v3->index], tface->uv[2]);
+ VECCOPY(ftang+6, vtang);
+ Normalize(ftang+6);
+ if(v4) {
+ vtang= find_vertex_tangent(vtangents[v4->index], tface->uv[3]);
+ VECCOPY(ftang+9, vtang);
+ Normalize(ftang+9);
+ }
+ }
+ }
}
/* normalize vertex normals */
@@ -636,94 +665,12 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent)
}
}
}
-}
-// NT same as calc_vertexnormals, but dont modify the existing vertex normals
-// only recalculate other render data. If this is at some point used for other things than fluidsim,
-// this could be made on option for the normal calc_vertexnormals
-static void calc_fluidsimnormals(Render *re, ObjectRen *obr, int do_tangent)
-{
- int a;
-
- /* dont clear vertex normals here */
- // OFF for(a=0; a<obr->totvert; a++) { VertRen *ver= RE_findOrAddVert(obr, a); ver->n[0]=ver->n[1]=ver->n[2]= 0.0; }
- /* 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(vlr->flag & ME_SMOOTH) {
- VertRen *v1= vlr->v1;
- VertRen *v2= vlr->v2;
- VertRen *v3= vlr->v3;
- VertRen *v4= vlr->v4;
- float n1[3], n2[3], n3[3], n4[3];
- float fac1, fac2, fac3, fac4=0.0f;
-
- if(re->flag & R_GLOB_NOPUNOFLIP)
- vlr->flag |= R_NOPUNOFLIP;
-
- VecSubf(n1, v2->co, v1->co);
- Normalize(n1);
- VecSubf(n2, v3->co, v2->co);
- Normalize(n2);
- if(v4==NULL) {
- VecSubf(n3, v1->co, v3->co);
- Normalize(n3);
- fac1= saacos(-n1[0]*n3[0]-n1[1]*n3[1]-n1[2]*n3[2]);
- fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
- }
- else {
- VecSubf(n3, v4->co, v3->co);
- Normalize(n3);
- VecSubf(n4, v1->co, v4->co);
- Normalize(n4);
- fac1= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
- fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
- fac4= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
-
- if(!(vlr->flag & R_NOPUNOFLIP)) {
- if( check_vnormal(vlr->n, v4->n) ) fac4= -fac4;
- }
- }
-
- //if(do_tangent)
- // calc_tangent_vector(obr, vlr, fac1, fac2, fac3, fac4);
- }
- 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 solid faces */
- for(a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
- if((vlr->flag & ME_SMOOTH)==0) {
- float *f1= vlr->v1->n;
- if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
- f1= vlr->v2->n;
- if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
- f1= vlr->v3->n;
- if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
- if(vlr->v4) {
- f1= vlr->v4->n;
- if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
- }
- }
- }
-
- /* normalize vertex normals */
- for(a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- Normalize(ver->n);
- if(do_tangent) {
- float *tav= RE_vertren_get_tangent(obr, ver, 0);
- if(tav) Normalize(tav);
- }
- }
+ if(arena)
+ BLI_memarena_free(arena);
+ if(vtangents)
+ MEM_freeN(vtangents);
}
/* ------------------------------------------------------------------------- */
@@ -926,6 +873,8 @@ static float *get_object_orco(Render *re, Object *ob)
orco = make_orco_curve(ob);
} else if (ob->type==OB_SURF) {
orco = make_orco_surf(ob);
+ } else if (ob->type==OB_MBALL) {
+ orco = make_orco_mball(ob);
}
if (orco)
@@ -951,6 +900,26 @@ static void free_mesh_orco_hash(Render *re)
}
}
+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_ZTRA)
+ 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, int nr)
{
extern Material defmaterial; /* material.c */
@@ -959,14 +928,17 @@ static Material *give_render_material(Render *re, Object *ob, int nr)
ma= give_current_material(ob, nr);
if(ma==NULL)
ma= &defmaterial;
- else
- if(ma->mode & MA_ZTRA)
- re->flag |= R_ZTRA;
if(re->r.mode & R_SPEED) ma->texco |= NEED_UV;
+ if(ma->mode & MA_ZTRA)
+ re->flag |= R_ZTRA;
+
/* for light groups */
ma->flag |= MA_IS_USED;
+
+ if(ma->nodetree && ma->use_nodes)
+ flag_render_node_material(re, ma->nodetree);
return ma;
}
@@ -977,7 +949,7 @@ static Material *give_render_material(Render *re, Object *ob, int nr)
/* future thread problem... */
static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, float *orco, float *surfnor,
- float *uvco, int totuv, float *vec, float *vec1, float ctime,
+ float *uvco, int totuv, MCol *mcol, int totcol, float *vec, float *vec1, float ctime,
int first, int line, int adapt, float adapt_angle, float adapt_pix, int override_uv)
{
static VertRen *v1= NULL, *v2= NULL;
@@ -1040,7 +1012,6 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
if(line) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->flag= flag;
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
@@ -1074,7 +1045,6 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
vlr->mat= ma;
vlr->ec= ME_V2V3;
- vlr->lay= obr->ob->lay;
if(surfnor) {
float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
@@ -1101,6 +1071,14 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
mtf->uv[2][1]=mtf->uv[3][1]=1.0f;
}
}
+ if(mcol){
+ for(i=0; i<totcol; i++){
+ MCol *mc;
+ mc=RE_vlakren_get_mcol(obr,vlr,i,NULL,1);
+ mc[0]=mc[1]=mc[2]=mc[3]=mcol[i];
+ mc[0]=mc[1]=mc[2]=mc[3]=mcol[i];
+ }
+ }
}
/* first two vertices of a strand */
else if(first) {
@@ -1130,7 +1108,6 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
if(adapt==0 || second){
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->flag= flag;
- vlr->obr= obr;
vlr->v1= v1;
vlr->v2= v2;
vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
@@ -1160,7 +1137,6 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
if(Inpf(anor,nor)<adapt_angle && w>adapt_pix){
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->flag= flag;
- vlr->obr= obr;
vlr->v1= v1;
vlr->v2= v2;
vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
@@ -1193,7 +1169,6 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
vlr->mat= ma;
vlr->ec= ME_V2V3;
- vlr->lay= obr->ob->lay;
if(surfnor) {
float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
@@ -1220,6 +1195,14 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
mtf->uv[2][1]=mtf->uv[3][1]=(vlr->v3->accum+1.0f)/2.0f;
}
}
+ if(mcol){
+ for(i=0; i<totcol; i++){
+ MCol *mc;
+ mc=RE_vlakren_get_mcol(obr,vlr,i,NULL,1);
+ mc[0]=mc[1]=mc[2]=mc[3]=mcol[i];
+ mc[0]=mc[1]=mc[2]=mc[3]=mcol[i];
+ }
+ }
}
}
@@ -1230,7 +1213,6 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float
if(line) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
vlr->v3= vlr->v2;
@@ -1246,7 +1228,6 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float
vlr->mat= ma;
vlr->ec= ME_V1V2;
- vlr->lay= obr->ob->lay;
}
else if(first) {
@@ -1255,7 +1236,6 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float
}
else {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= v1;
vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
vlr->v3= vlr->v2;
@@ -1270,7 +1250,6 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float
vlr->mat= ma;
vlr->ec= ME_V1V2;
- vlr->lay= obr->ob->lay;
}
}
@@ -1287,7 +1266,6 @@ static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, Object
onevec[align]=1.0f;
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
@@ -1370,7 +1348,6 @@ static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, Object
vlr->mat= ma;
vlr->ec= ME_V2V3;
- vlr->lay= obr->ob->lay;
if(uv_split>1){
uvdx=uvdy=1.0f/(float)uv_split;
@@ -1456,7 +1433,8 @@ static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, Object
}
static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, int path, int first, int line,
float time, float *loc, float *loc1, float *orco, float *surfnor, int totuv, float *uvco,
- float size, int seed, int override_uv, int adapt, float adapt_angle, float adapt_pix)
+ int totcol, MCol *mcol, float size, int seed, int override_uv,
+ int adapt, float adapt_angle, float adapt_pix)
{
HaloRen *har=0;
if(path){
@@ -1467,19 +1445,18 @@ static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mat
if(har) har->lay= obr->ob->lay;
}
else
- static_particle_strand(re, obr, ma, orco, surfnor, uvco, totuv, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv);
+ static_particle_strand(re, obr, ma, orco, surfnor, uvco, totuv, mcol, totcol, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv);
}
else{
har= RE_inithalo_particle(re, obr, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed);
if(har) har->lay= obr->ob->lay;
}
}
-static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys)
+static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset)
{
Object *ob= obr->ob;
Object *tob=0, *bb_ob=re->scene->camera;
Material *ma=0;
- CustomDataLayer *layer;
MTFace *mtface;
ParticleSystemModifierData *psmd;
ParticleSystem *tpsys=0;
@@ -1490,21 +1467,25 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
ParticleCacheKey *cache=0;
StrandBuffer *strandbuf=0;
StrandVert *svert=0;
+ StrandBound *sbound= 0;
StrandRen *strand=0;
RNG *rng= 0;
+ MCol *mcol= 0;
float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time;
float *orco=0,*surfnor=0,*uvco=0, strandlen=0.0f, curlen=0.0f;
float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0);
- float loc_tex[3], size_tex[3], adapt_angle=0.0, adapt_pix=0.0, random;
- float simplify[2];
- int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0;
- int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild;
- int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0};
+ float adapt_angle=0.0, adapt_pix=0.0, random, simplify[2];
+ int i, a, k, max_k=0, totpart, totuv=0, totcol=0, override_uv=-1, dosimplify = 0, dosurfacecache = 0;
+ int path_possible=0, keys_possible=0, baked_keys=0, totchild=0;
+ int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0}, num;
+ int totface, *origindex = 0;
char **uv_name=0;
/* 1. check that everything is ok & updated */
if(psys==NULL)
return 0;
+
+ totchild=psys->totchild;
part=psys->part;
pars=psys->particles;
@@ -1547,6 +1528,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
RE_set_customdata_names(obr, &psmd->dm->faceData);
totuv=CustomData_number_of_layers(&psmd->dm->faceData,CD_MTFACE);
+ totcol=CustomData_number_of_layers(&psmd->dm->faceData,CD_MCOL);
if(ma->texco & TEXCO_UV && totuv) {
uvco = MEM_callocN(totuv*2*sizeof(float),"particle_uvs");
@@ -1557,6 +1539,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
}
+ if(totcol)
+ mcol = MEM_callocN(totcol*sizeof(MCol),"particle_mcols");
+
if(part->draw_as==PART_DRAW_BB){
int first_uv=CustomData_get_layer_index(&psmd->dm->faceData,CD_MTFACE);
@@ -1607,8 +1592,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
totpart=psys->totpart;
- mesh_get_texspace(ob->data, loc_tex, NULL, size_tex);
-
if(psys->pathcache){
path_possible=1;
keys_possible=1;
@@ -1645,12 +1628,37 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
strandbuf->overrideuv= override_uv;
strandbuf->minwidth= ma->strand_min;
+ if(ma->strand_widthfade == 0.0f)
+ strandbuf->widthfade= 0.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)
+ dosurfacecache= 1;
+ else if((re->wrld.mode & WO_AMB_OCC) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ if(ma->amb != 0.0f)
+ dosurfacecache= 1;
+
+ totface= psmd->dm->getNumFaces(psmd->dm);
+ origindex= psmd->dm->getFaceDataArray(psmd->dm, CD_ORIGINDEX);
+ if(origindex) {
+ for(a=0; a<totface; a++)
+ strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]);
+ strandbuf->totbound++;
+ }
+ strandbuf->totbound++;
+ strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
+ sbound= strandbuf->bound;
+ sbound->start= sbound->end= 0;
}
}
}
@@ -1669,7 +1677,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
psys->lattice=psys_get_lattice(ob,psys);
/* 3. start creating renderable things */
- for(a=0,pa=pars; a<totpart+totchild; a++, pa++) {
+ for(a=0,pa=pars; a<totpart+totchild; a++, pa++, seed++) {
random = rng_getFloat(rng);
if(a<totpart){
@@ -1694,20 +1702,43 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
/* get orco */
if(tpsys && (part->from==PART_FROM_PARTICLE || part->phystype==PART_PHYS_NO)){
tpa=tpsys->particles+pa->num;
- psys_particle_on_emitter(ob, psmd,tpart->from,tpa->num, -1,tpa->fuv,tpa->foffset,co,nor,0,0,orco,0);
+ psys_particle_on_emitter(psmd,tpart->from,tpa->num,pa->num_dmcache,tpa->fuv,tpa->foffset,co,nor,0,0,orco,0);
}
else
- psys_particle_on_emitter(ob, psmd,part->from,pa->num,-1,pa->fuv,pa->foffset,co,nor,0,0,orco,0);
+ psys_particle_on_emitter(psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,0);
+
+ num= pa->num_dmcache;
+
+ if(num == DMCACHE_NOTFOUND)
+ if(pa->num < psmd->dm->getNumFaces(psmd->dm))
+ num= pa->num;
if(uvco && ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)){
- layer=psmd->dm->faceData.layers + CustomData_get_layer_index(&psmd->dm->faceData,CD_MFACE);
for(i=0; i<totuv; i++){
- MFace *mface=psmd->dm->getFaceData(psmd->dm,pa->num,CD_MFACE);
-
- mtface=(MTFace*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MTFACE,i);
- mtface+=pa->num;
-
- psys_interpolate_uvs(mtface,mface->v4,pa->fuv,uvco+2*i);
+ if(num != DMCACHE_NOTFOUND) {
+ MFace *mface=psmd->dm->getFaceData(psmd->dm,num,CD_MFACE);
+ mtface=(MTFace*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MTFACE,i);
+ mtface+=num;
+
+ psys_interpolate_uvs(mtface,mface->v4,pa->fuv,uvco+2*i);
+ }
+ else {
+ uvco[2*i]= 0.0f;
+ uvco[2*i + 1]= 0.0f;
+ }
+ }
+ }
+ if(mcol && ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)){
+ for(i=0; i<totcol; i++){
+ if(num != DMCACHE_NOTFOUND) {
+ MFace *mface=psmd->dm->getFaceData(psmd->dm,num,CD_MFACE);
+ MCol *mc=(MCol*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MCOL,i);
+ mc+=num*4;
+
+ psys_interpolate_mcol(mc,mface->v4,pa->fuv,mcol+i);
+ }
+ else
+ memset(&mcol[i], 0, sizeof(MCol));
}
}
@@ -1744,14 +1775,22 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
r_tilt=2.0f*cpa->rand[2];
+ num= cpa->num;
+
/* get orco */
- psys_particle_on_emitter(ob, psmd,
- (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE,
- cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,nor,0,0,orco,0);
+ if(part->childtype == PART_CHILD_FACES) {
+ psys_particle_on_emitter(psmd,
+ PART_FROM_FACE, cpa->num,DMCACHE_ISCHILD,
+ cpa->fuv,cpa->foffset,co,nor,0,0,orco,0);
+ }
+ else {
+ ParticleData *par = psys->particles + cpa->parent;
+ psys_particle_on_emitter(psmd, part->from,
+ par->num,DMCACHE_ISCHILD,par->fuv,
+ par->foffset,co,nor,0,0,orco,0);
+ }
if(uvco){
- layer=psmd->dm->faceData.layers + CustomData_get_layer_index(&psmd->dm->faceData,CD_MFACE);
-
if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
for(i=0; i<totuv; i++){
if(part->childtype==PART_CHILD_FACES){
@@ -1768,30 +1807,77 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
}
else if(ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)){
- for(i=0; i<totuv; i++){
- ParticleData *parent = psys->particles+cpa->parent;
- MFace *mface=psmd->dm->getFaceData(psmd->dm,parent->num,CD_MFACE);
+ ParticleData *parent = psys->particles + cpa->parent;
+ num= parent->num_dmcache;
- mtface=(MTFace*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MTFACE,i);
- mtface+=parent->num;
-
- psys_interpolate_uvs(mtface,mface->v4,parent->fuv,uvco+2*i);
+ if(num == DMCACHE_NOTFOUND)
+ if(parent->num < psmd->dm->getNumFaces(psmd->dm))
+ num= parent->num;
+
+ for(i=0; i<totuv; i++) {
+ if(num != DMCACHE_NOTFOUND) {
+ MFace *mface=psmd->dm->getFaceData(psmd->dm,num,CD_MFACE);
+ mtface=(MTFace*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MTFACE,i);
+ mtface+=num;
+ psys_interpolate_uvs(mtface,mface->v4,parent->fuv,uvco+2*i);
+ }
+ else {
+ uvco[2*i]= 0.0f;
+ uvco[2*i + 1]= 0.0f;
+ }
+ }
+ }
+ }
+
+ if(mcol){
+ if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
+ for(i=0; i<totcol; i++){
+ if(part->childtype==PART_CHILD_FACES){
+ MFace *mface=psmd->dm->getFaceData(psmd->dm,cpa->num,CD_MFACE);
+ MCol *mc=(MCol*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MCOL,i);
+ mc+=cpa->num*4;
+
+ psys_interpolate_mcol(mc,mface->v4,cpa->fuv,mcol+i);
+ }
+ else
+ memset(&mcol[i], 0, sizeof(MCol));
+ }
+ }
+ else if(ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)){
+ ParticleData *parent = psys->particles + cpa->parent;
+ num= parent->num_dmcache;
+
+ if(num == DMCACHE_NOTFOUND)
+ if(parent->num < psmd->dm->getNumFaces(psmd->dm))
+ num= parent->num;
+
+ for(i=0; i<totcol; i++){
+ if(num != DMCACHE_NOTFOUND) {
+ MFace *mface=psmd->dm->getFaceData(psmd->dm,num,CD_MFACE);
+ MCol *mc=(MCol*)CustomData_get_layer_n(&psmd->dm->faceData,CD_MCOL,i);
+ mc+=num*4;
+
+ psys_interpolate_mcol(mc,mface->v4,parent->fuv,mcol+i);
+ }
+ else
+ memset(&mcol[i], 0, sizeof(MCol));
}
}
}
dosimplify= psys_render_simplify_params(psys, cpa, simplify);
- if(path_nbr) {
+ if(path_nbr && psys->childcache) {
cache = psys->childcache[a-totpart];
max_k = (int)cache->steps;
}
- }
- if(orco) {
- orco[0] = (orco[0]-loc_tex[0])/size_tex[0];
- orco[1] = (orco[1]-loc_tex[1])/size_tex[1];
- orco[2] = (orco[2]-loc_tex[2])/size_tex[2];
+ if(strandbuf) {
+ if(origindex[cpa->num]+1 > sbound - strandbuf->bound) {
+ sbound= strandbuf->bound + origindex[cpa->num]+1;
+ sbound->start= sbound->end= obr->totstrand;
+ }
+ }
}
/* surface normal shading setup */
@@ -1820,8 +1906,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
VECCOPY(snor, surfnor);
}
- if(uvco){
- for(i=0; i<totuv; i++){
+ if(dosurfacecache && num >= 0) {
+ int *facenum= RE_strandren_get_face(obr, strand, 1);
+ *facenum= num;
+ }
+
+ if(uvco) {
+ for(i=0; i<totuv; i++) {
if(i != override_uv) {
float *uv= RE_strandren_get_uv(obr, strand, i, NULL, 1);
@@ -1830,6 +1921,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
}
}
+ if(mcol) {
+ for(i=0; i<totcol; i++) {
+ MCol *mc= RE_strandren_get_mcol(obr, strand, i, NULL, 1);
+ *mc = mcol[i];
+ }
+ }
+
+ sbound->end++;
}
/* strandco computation setup */
@@ -1879,7 +1978,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
VECADDFAC(loc1,loc,vel,part->draw_line[1]);
render_new_particle(re,obr,psmd->dm,ma,1,0,1,0.0f,loc0,loc1,
- orco,surfnor,totuv,uvco,hasize,seed,override_uv,0,0,0);
+ orco,surfnor,totuv,uvco,totcol,mcol,hasize,seed,override_uv,0,0,0);
}
else if(part->draw_as==PART_DRAW_BB) {
VECCOPY(vel,state.vel);
@@ -1899,13 +1998,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
VECSUB(loc0,loc1,loc);
VECADD(loc0,loc1,loc0);
render_new_particle(re,obr,psmd->dm,ma,path,1,0,0.0f,loc1,loc0,
- orco,surfnor,totuv,uvco,hasize,seed,override_uv,
+ orco,surfnor,totuv,uvco,totcol,mcol,hasize,seed,override_uv,
adapt,adapt_angle,adapt_pix);
}
if(path_nbr==0 || k)
render_new_particle(re,obr,psmd->dm,ma,path,0,0,time,loc,loc1,
- orco,surfnor,totuv,uvco,hasize,seed,override_uv,
+ orco,surfnor,totuv,uvco,totcol,mcol,hasize,seed,override_uv,
adapt,adapt_angle,adapt_pix);
VECCOPY(loc1,loc);
@@ -1919,6 +2018,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
break;
}
+ if(dosurfacecache)
+ strandbuf->surface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset);
+
/* 4. clean up */
if(ma) do_mat_ipo(ma);
@@ -1927,6 +2029,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if(uvco)
MEM_freeN(uvco);
+
+ if(mcol)
+ MEM_freeN(mcol);
if(uv_name)
MEM_freeN(uv_name);
@@ -1944,7 +2049,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
if(path && (ma->mode_l & MA_TANGENT_STR)==0)
- calc_vertexnormals(re, obr, 0);
+ calc_vertexnormals(re, obr, 0, 0);
return 1;
}
@@ -2005,7 +2110,8 @@ static void make_render_halos(Render *re, ObjectRen *obr, Mesh *me, int totvert,
static int verghalo(const void *a1, const void *a2)
{
- const HaloRen *har1= a1, *har2= 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;
@@ -2053,11 +2159,11 @@ static short test_for_displace(Render *re, Object *ob)
return 0;
}
-static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
+static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale, float mat[][4], float imat[][3])
{
MTFace *tface;
short texco= shi->mat->texco;
- float sample=0;
+ float sample=0, displace[3];
char *name;
int i;
@@ -2066,6 +2172,15 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
/* vertex normal is used for textures type 'col' and 'var' */
VECCOPY(shi->vn, vr->n);
+ if(mat)
+ Mat4MulVecfl(mat, shi->co);
+
+ if(imat) {
+ shi->vn[0]= imat[0][0]*vr->n[0]+imat[0][1]*vr->n[1]+imat[0][2]*vr->n[2];
+ shi->vn[1]= imat[1][0]*vr->n[0]+imat[1][1]*vr->n[1]+imat[1][2]*vr->n[2];
+ shi->vn[2]= imat[2][0]*vr->n[0]+imat[2][1]*vr->n[1]+imat[2][2]*vr->n[2];
+ }
+
if (texco & TEXCO_UV) {
shi->totuv= 0;
shi->actuv= obr->actmtface;
@@ -2111,11 +2226,18 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
//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];
+ if(mat)
+ Mat3MulVecfl(imat, displace);
+
/* 0.5 could become button once? */
- vr->co[0] += shi->displace[0] * scale[0] ;
- vr->co[1] += shi->displace[1] * scale[1] ;
- vr->co[2] += shi->displace[2] * scale[2] ;
+ 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]);
@@ -2133,28 +2255,36 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
return;
}
-static void displace_render_face(Render *re, VlakRen *vlr, float *scale)
+static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale, float mat[][4], float imat[][3])
{
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() */
- shi.osatex= 0; /* signal not to use dx[] and dy[] texture AA vectors */
+
+ /* memset above means we dont need this */
+ /*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */
+
shi.vlr= vlr; /* current render face */
shi.mat= vlr->mat; /* current input material */
/* Displace the verts, flag is set when done */
if (!vlr->v1->flag)
- displace_render_vert(re, vlr->obr, &shi, vlr->v1,0, scale);
+ displace_render_vert(re, obr, &shi, vlr->v1,0, scale, mat, imat);
if (!vlr->v2->flag)
- displace_render_vert(re, vlr->obr, &shi, vlr->v2, 1, scale);
+ displace_render_vert(re, obr, &shi, vlr->v2, 1, scale, mat, imat);
if (!vlr->v3->flag)
- displace_render_vert(re, vlr->obr, &shi, vlr->v3, 2, scale);
+ displace_render_vert(re, obr, &shi, vlr->v3, 2, scale, mat, imat);
if (vlr->v4) {
if (!vlr->v4->flag)
- displace_render_vert(re, vlr->obr, &shi, vlr->v4, 3, scale);
+ displace_render_vert(re, obr, &shi, vlr->v4, 3, scale, mat, imat);
/* closest in displace value. This will help smooth edges. */
if ( fabs(vlr->v1->accum - vlr->v3->accum) > fabs(vlr->v2->accum - vlr->v4->accum))
@@ -2171,7 +2301,7 @@ static void displace_render_face(Render *re, VlakRen *vlr, float *scale)
}
}
-static void do_displacement(Render *re, ObjectRen *obr)
+static void do_displacement(Render *re, ObjectRen *obr, float mat[][4], float imat[][3])
{
VertRen *vr;
VlakRen *vlr;
@@ -2196,11 +2326,11 @@ static void do_displacement(Render *re, ObjectRen *obr)
for(i=0; i<obr->totvlak; i++){
vlr=RE_findOrAddVlak(obr, i);
- displace_render_face(re, vlr, scale);
+ displace_render_face(re, obr, vlr, scale, mat, imat);
}
/* Recalc vertex normals */
- calc_vertexnormals(re, obr, 0);
+ calc_vertexnormals(re, obr, 0, 0);
}
/* ------------------------------------------------------------------------- */
@@ -2214,8 +2344,8 @@ static void init_render_mball(Render *re, ObjectRen *obr)
VertRen *ver;
VlakRen *vlr, *vlr1;
Material *ma;
- float *data, *nors, mat[4][4], imat[3][3], xn, yn, zn;
- int a, need_orco, *index;
+ float *data, *nors, *orco, mat[4][4], imat[3][3], xn, yn, zn;
+ int a, need_orco, vlakindex, *index;
if (ob!=find_basis_mball(ob))
return;
@@ -2237,8 +2367,9 @@ static void init_render_mball(Render *re, ObjectRen *obr)
data= dl->verts;
nors= dl->nors;
+ orco= get_object_orco(re, ob);
- for(a=0; a<dl->nr; a++, data+=3, nors+=3) {
+ for(a=0; a<dl->nr; a++, data+=3, nors+=3, orco+=3) {
ver= RE_findOrAddVert(obr, obr->totvert++);
VECCOPY(ver->co, data);
@@ -2256,14 +2387,13 @@ static void init_render_mball(Render *re, ObjectRen *obr)
Normalize(ver->n);
//if(ob->transflag & OB_NEG_SCALE) VecMulf(ver->n. -1.0);
- if(need_orco) ver->orco= data;
+ if(need_orco) ver->orco= orco;
}
index= dl->index;
for(a=0; a<dl->parts; a++, index+=4) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, index[0]);
vlr->v2= RE_findOrAddVert(obr, index[1]);
vlr->v3= RE_findOrAddVert(obr, index[2]);
@@ -2277,12 +2407,13 @@ static void init_render_mball(Render *re, ObjectRen *obr)
vlr->mat= ma;
vlr->flag= ME_SMOOTH+R_NOPUNOFLIP;
vlr->ec= 0;
- vlr->lay= ob->lay;
/* 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(ob->transflag & OB_NEG_SCALE)
@@ -2292,14 +2423,8 @@ static void init_render_mball(Render *re, ObjectRen *obr)
}
}
- if(need_orco) {
- /* store displist and scale */
- make_orco_mball(ob);
- }
- else {
- /* enforce display lists remade */
- freedisplist(&ob->disp);
- }
+ /* enforce display lists remade */
+ freedisplist(&ob->disp);
/* this enforces remake for real, orco displist is small (in scale) */
ob->recalc |= OB_RECALC_DATA;
@@ -2316,7 +2441,7 @@ static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar,
VertRen *v1, *v2, *v3, *v4, *ver;
VlakRen *vlr, *vlr1, *vlr2, *vlr3;
Curve *cu= ob->data;
- float *data, n1[3], flen;
+ float *data, n1[3];
int u, v, orcoret= 0;
int p1, p2, p3, p4, a;
int sizeu, nsizeu, sizev, nsizev;
@@ -2386,13 +2511,12 @@ static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar,
v4= RE_findOrAddVert(obr, p4);
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
- flen= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1);
+ CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1);
+
VECCOPY(vlr->n, n1);
- vlr->lay= ob->lay;
vlr->mat= matar[ dl->col];
vlr->ec= ME_V1V2+ME_V2V3;
vlr->flag= dl->rt;
@@ -2524,7 +2648,7 @@ static void init_render_surf(Render *re, ObjectRen *obr)
freedisplist(&displist);
}
-static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
+static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
Curve *cu;
@@ -2539,7 +2663,8 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
int frontside, need_orco=0;
cu= ob->data;
- if(cu->nurb.first==NULL) return;
+ if(ob->type==OB_FONT && cu->str==NULL) return;
+ else if(ob->type==OB_CURVE && cu->nurb.first==NULL) return;
/* no modifier call here, is in makedisp */
@@ -2602,13 +2727,12 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
}
}
- if(only_verts==0) {
+ if(timeoffset==0) {
startvlak= obr->totvlak;
index= dl->index;
for(a=0; a<dl->parts; a++, index+=3) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr = obr;
vlr->v1= RE_findOrAddVert(obr, startvert+index[0]);
vlr->v2= RE_findOrAddVert(obr, startvert+index[1]);
vlr->v3= RE_findOrAddVert(obr, startvert+index[2]);
@@ -2627,7 +2751,6 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
vlr->flag |= R_NOPUNOFLIP;
}
vlr->ec= 0;
- vlr->lay= ob->lay;
}
}
}
@@ -2657,14 +2780,16 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
}
}
- if(dl->bevelSplitFlag || only_verts==0) {
+ if(dl->bevelSplitFlag || timeoffset==0) {
startvlak= obr->totvlak;
for(a=0; a<dl->parts; a++) {
frontside= (a >= dl->nr/2);
-
- DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+
+ if (surfindex_displist(dl, a, &b, &p1, &p2, &p3, &p4)==0)
+ break;
+
p1+= startvert;
p2+= startvert;
p3+= startvert;
@@ -2672,7 +2797,6 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
for(; b<dl->nr; b++) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, p2);
vlr->v2= RE_findOrAddVert(obr, p1);
vlr->v3= RE_findOrAddVert(obr, p3);
@@ -2681,7 +2805,6 @@ static void init_render_curve(Render *re, ObjectRen *obr, int only_verts)
if(a==0) vlr->ec+= ME_V1V2;
vlr->flag= dl->rt;
- vlr->lay= ob->lay;
/* this is not really scientific: the vertices
* 2, 3 en 4 seem to give better vertexnormals than 1 2 3:
@@ -2875,7 +2998,7 @@ static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge,
}
}
-static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
+static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
Mesh *me;
@@ -2889,9 +3012,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
CustomDataMask mask;
float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
float *orco=0;
- int a, a1, ok, need_orco=0, need_stress=0, need_tangent=0, vertofs;
+ int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0;
+ int a, a1, ok, vertofs;
int end, do_autosmooth=0, totvert = 0;
- int useFluidmeshNormals= 0; // NT fluidsim, use smoothed normals?
int use_original_normals= 0;
me= ob->data;
@@ -2912,11 +3035,19 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
if(ma->texco & TEXCO_STRESS)
need_stress= 1;
/* normalmaps, test if tangents needed, separated from shading */
- if ((ma->mode_l & MA_TANGENT_V) || (ma->mode_l & MA_NORMAP_TANG)) {
+ if(ma->mode_l & MA_TANGENT_V) {
need_tangent= 1;
if(me->mtface==NULL)
need_orco= 1;
}
+ if(ma->mode_l & MA_NORMAP_TANG) {
+ if(me->mtface==NULL) {
+ need_orco= 1;
+ need_tangent= 1;
+ }
+ need_nmap_tangent= 1;
+ }
+
/* radio faces need autosmooth, to separate shared vertices in corners */
if(re->r.mode & R_RADIO)
if(ma->mode & MA_RADIO)
@@ -2926,23 +3057,32 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
if(re->flag & R_NEED_TANGENT) {
/* exception for tangent space baking */
- need_tangent= 1;
- if(me->mtface==NULL)
+ if(me->mtface==NULL) {
need_orco= 1;
+ need_tangent= 1;
+ }
+ need_nmap_tangent= 1;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize */
do_autosmooth |= (me->flag & ME_AUTOSMOOTH);
if(do_autosmooth)
- only_verts= 0;
+ timeoffset= 0;
if(test_for_displace(re, ob ) )
- only_verts= 0;
+ timeoffset= 0;
mask= CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL;
- if(!only_verts)
+ if(!timeoffset)
if(need_orco)
mask |= CD_MASK_ORCO;
+ if(me->mr) {
+ if(re->flag & R_SKIP_MULTIRES)
+ me->mr->flag |= MULTIRES_NO_RENDER;
+ else
+ me->mr->flag &= ~MULTIRES_NO_RENDER;
+ }
+
dm= mesh_create_derived_render(ob, mask);
if(dm==NULL) return; /* in case duplicated object fails? */
@@ -2954,12 +3094,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
}
}
- if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
- (ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)&&
- (ob->fluidsimSettings->meshSurface) ) {
- useFluidmeshNormals = 1;
- }
-
mvert= dm->getVertArray(dm);
totvert= dm->getNumVerts(dm);
@@ -2982,17 +3116,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
if(do_autosmooth==0) /* autosmooth on original unrotated data to prevent differences between frames */
MTC_Mat4MulVecfl(mat, ver->co);
- if(useFluidmeshNormals) {
- /* normals are inverted in render */
- xn = -mvert->no[0]/ 32767.0;
- yn = -mvert->no[1]/ 32767.0;
- zn = -mvert->no[2]/ 32767.0;
- /* transfor to cam space */
- 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;
- } // useFluidmeshNormals
-
if(orco) {
ver->orco= orco;
orco+=3;
@@ -3005,7 +3128,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
}
}
- if(!only_verts) {
+ if(!timeoffset) {
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
@@ -3052,7 +3175,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
flag= mface->flag & ME_SMOOTH;
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
@@ -3082,7 +3204,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
vlr->flag |= R_NOPUNOFLIP;
}
vlr->ec= 0; /* mesh edges rendered separately */
- vlr->lay= ob->lay;
if(len==0) obr->totvlak--;
else {
@@ -3133,7 +3254,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
MVert *v1 = &mvert[medge->v2];
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->obr= obr;
vlr->v1= RE_findOrAddVert(obr, vertofs+medge->v1);
vlr->v2= RE_findOrAddVert(obr, vertofs+medge->v2);
vlr->v3= vlr->v2;
@@ -3154,7 +3274,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
vlr->mat= ma;
vlr->flag= 0;
vlr->ec= ME_V1V2;
- vlr->lay= ob->lay;
}
}
if(edgetable)
@@ -3163,22 +3282,20 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int only_verts)
}
}
- if(!only_verts) {
+ if(!timeoffset) {
if (test_for_displace(re, ob ) ) {
- calc_vertexnormals(re, obr, 0);
- do_displacement(re, obr);
+ calc_vertexnormals(re, obr, 0, 0);
+ if(do_autosmooth)
+ do_displacement(re, obr, mat, imat);
+ else
+ do_displacement(re, obr, NULL, NULL);
}
if(do_autosmooth) {
autosmooth(re, obr, mat, me->smoothresh);
}
- if(useFluidmeshNormals) {
- // do not recalculate, only init render data
- calc_fluidsimnormals(re, obr, need_tangent);
- } else {
- calc_vertexnormals(re, obr, need_tangent);
- }
+ calc_vertexnormals(re, obr, need_tangent, need_nmap_tangent);
if(need_stress)
calc_edge_stress(re, obr, me);
@@ -3209,8 +3326,6 @@ static void initshadowbuf(Render *re, LampRen *lar, float mat[][4])
/* percentage render: keep track of min and max */
shb->size= (lar->bufsize*re->r.size)/100;
- if(lar->buffers>1) shb->size/= 2;
-
if(shb->size<512) shb->size= 512;
else if(shb->size > lar->bufsize) shb->size= lar->bufsize;
@@ -3282,6 +3397,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
LampRen *lar;
GroupObject *go;
float mat[4][4], angle, xn, yn;
+ float vec[3];
int c;
/* previewrender sets this to zero... prevent accidents */
@@ -3341,6 +3457,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
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
@@ -3353,12 +3472,20 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
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(ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
+ if (ELEM3(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( ELEM3(lar->type, LA_SPOT, LA_SUN, LA_LOCAL)) {
+ 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;
@@ -3388,6 +3515,27 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
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;
+
+ VECCOPY(vec,ob->obmat[2]);
+ Normalize(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;
#ifndef DISABLE_YAFRAY
@@ -3465,7 +3613,10 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
for(c=0; c<MAX_MTEX; c++) {
if(la->mtex[c] && la->mtex[c]->tex) {
- lar->mode |= LA_TEXTURE;
+ 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.rendering) {
if(re->osa) {
@@ -3485,9 +3636,6 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
if(re->r.mode & R_SHADOW) {
- if ((lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_HAMMERSLEY)) {
- init_lamp_hammersley(lar);
- }
if(la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) {
init_jitter_plane(lar);
}
@@ -3501,16 +3649,24 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
/* 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, tot= re->r.threads*re->r.osa;
+ int a, b;
+
+ memset(re->shadowsamplenr, 0, sizeof(re->shadowsamplenr));
lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
- lss= lar->shadsamp[0].s;
+ ls= lar->shadsamp;
+
/* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
- for(a=0; a<tot; a++, lss++) {
- for(b=0; b<4; b++) {
+ 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[b]= 1.0f;
+ lss->shadfac[0]= 1.0f;
+ lss->shadfac[1]= 1.0f;
+ lss->shadfac[2]= 1.0f;
+ lss->shadfac[3]= 1.0f;
}
}
}
@@ -3611,13 +3767,18 @@ void init_render_world(Render *re)
if(re->osa)
while(re->wrld.aosamp*re->wrld.aosamp < re->osa)
re->wrld.aosamp++;
- if(!(re->r.mode & R_RAYTRACE))
+ if(!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE))
re->wrld.mode &= ~WO_AMB_OCC;
}
else {
memset(&re->wrld, 0, sizeof(World));
- re->wrld.exp= 0.0;
- re->wrld.range= 1.0;
+ 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.0 + pow((2.0*re->wrld.exp + 0.5), -10);
@@ -3679,7 +3840,7 @@ static void set_phong_threshold(ObjectRen *obr)
}
/* per face check if all samples should be taken.
- if raytrace, do always for raytraced material, or when material full_osa set */
+ if raytrace or multisample, do always for raytraced material, or when material full_osa set */
static void set_fullsample_flag(Render *re, ObjectRen *obr)
{
VlakRen *vlr;
@@ -3693,7 +3854,8 @@ static void set_fullsample_flag(Render *re, ObjectRen *obr)
for(a=obr->totvlak-1; a>=0; a--) {
vlr= RE_findOrAddVlak(obr, a);
- if(vlr->mat->mode & MA_FULL_OSA) vlr->flag |= R_FULL_OSA;
+ if(vlr->mat->mode & MA_FULL_OSA)
+ vlr->flag |= R_FULL_OSA;
else if(trace) {
if(vlr->mat->mode & MA_SHLESS);
else if(vlr->mat->mode & (MA_RAYTRANSP|MA_RAYMIRROR))
@@ -3705,6 +3867,57 @@ static void set_fullsample_flag(Render *re, ObjectRen *obr)
}
}
+/* split quads for pradictable 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->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->mode & MA_WIRE)==0) {
+
+ 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;
+
+ /* new normals */
+ CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ CalcNormFloat(vlr1->v3->co, vlr1->v2->co, vlr1->v1->co, vlr1->n);
+ }
+ /* clear the flag when not divided */
+ else vlr->flag &= ~R_DIVIDE_24;
+ }
+ }
+}
+
static void check_non_flat_quads(ObjectRen *obr)
{
VlakRen *vlr, *vlr1;
@@ -3767,6 +3980,7 @@ static void check_non_flat_quads(ObjectRen *obr)
xn= nor[0]*vlr->n[0] + nor[1]*vlr->n[1] + nor[2]*vlr->n[2];
if(ABS(xn) < 0.999995 ) { // checked on noisy fractal grid
+
float d1, d2;
vlr1= RE_vlakren_copy(obr, vlr);
@@ -3778,10 +3992,10 @@ static void check_non_flat_quads(ObjectRen *obr)
CalcNormFloat(vlr->v2->co, vlr->v3->co, vlr->v4->co, nor);
d2= nor[0]*vlr->v2->n[0] + nor[1]*vlr->v2->n[1] + nor[2]*vlr->v2->n[2];
-
+
if( fabs(d1) < fabs(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;
@@ -3812,26 +4026,67 @@ static void check_non_flat_quads(ObjectRen *obr)
}
}
-static void finalize_render_object(Render *re, ObjectRen *obr, int only_verts)
+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))
- do_displacement(re, obr);
+ do_displacement(re, obr, NULL, NULL);
- if(!only_verts) {
+ 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);
-
- check_non_flat_quads(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 {
+ check_non_flat_quads(obr);
+ }
+
set_fullsample_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++;
+
+ DO_MINMAX(ver->co, min, max);
+ }
+
+ if(obr->strandbuf) {
+ 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);
+ }
+
+ VECCOPY(sbound->boundbox[0], smin);
+ VECCOPY(sbound->boundbox[1], smax);
+
+ DO_MINMAX(smin, min, max);
+ DO_MINMAX(smax, min, max);
+ }
+ }
+
+ VECCOPY(obr->boundbox[0], min);
+ VECCOPY(obr->boundbox[1], max);
}
}
}
@@ -3845,7 +4100,128 @@ static int render_object_type(int type)
return ELEM5(type, OB_FONT, OB_CURVE, OB_SURF, OB_MESH, OB_MBALL);
}
-static void init_render_object_data(Render *re, ObjectRen *obr, int only_verts)
+static void find_dupli_instances(Render *re, ObjectRen *obr)
+{
+ ObjectInstanceRen *obi;
+ float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
+ int first = 1;
+
+ Mat4MulMat4(obmat, obr->obmat, re->viewmat);
+ Mat4Invert(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 */
+ Mat4CpyMat4(obimat, obi->mat);
+ Mat4MulMat4(obi->mat, imat, obimat);
+
+ Mat3CpyMat4(nmat, obi->mat);
+ Mat3Inv(obi->nmat, nmat);
+ Mat3Transp(obi->nmat);
+
+ 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)
+{
+ float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
+
+ Mat4MulMat4(obmat, obr->obmat, re->viewmat);
+ Mat4Invert(imat, obmat);
+
+ obi->obr= obr;
+
+ /* compute difference between object matrix and
+ * object matrix with dupli transform, in viewspace */
+ Mat4CpyMat4(obimat, obi->mat);
+ Mat4MulMat4(obi->mat, imat, obimat);
+
+ Mat3CpyMat4(nmat, obi->mat);
+ Mat3Inv(obi->nmat, nmat);
+ Mat3Transp(obi->nmat);
+
+ 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)
+{
+ /* 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);
+ Mat4Invert(imat, dob->mat);
+ MTC_Mat4MulSerie(obi->duplitexmat, re->viewmat, dob->omat, imat, re->viewinv, 0, 0, 0, 0);
+ }
+}
+
+static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
ParticleSystem *psys;
@@ -3863,20 +4239,20 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int only_verts)
for(psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++)
psys= psys->next;
- render_new_particle_system(re, obr, psys);
+ render_new_particle_system(re, obr, psys, timeoffset);
}
else {
if ELEM(ob->type, OB_FONT, OB_CURVE)
- init_render_curve(re, obr, only_verts);
+ init_render_curve(re, obr, timeoffset);
else if(ob->type==OB_SURF)
init_render_surf(re, obr);
else if(ob->type==OB_MESH)
- init_render_mesh(re, obr, only_verts);
+ init_render_mesh(re, obr, timeoffset);
else if(ob->type==OB_MBALL)
init_render_mball(re, obr);
}
- finalize_render_object(re, obr, only_verts);
+ finalize_render_object(re, obr, timeoffset);
re->totvert += obr->totvert;
re->totvlak += obr->totvlak;
@@ -3884,11 +4260,14 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int only_verts)
re->totstrand += obr->totstrand;
}
-static void add_render_object(Render *re, Object *ob, Object *par, int index, int only_verts)
+static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, int timeoffset, int vectorlay)
{
ObjectRen *obr;
+ ObjectInstanceRen *obi;
ParticleSystem *psys;
- int show_emitter, allow_render= 1, psysindex;
+ int show_emitter, allow_render= 1, index, psysindex;
+
+ index= (dob)? dob->index: 0;
/* the emitter has to be processed first (render levels of modifiers) */
/* so here we only check if the emitter should be rendered */
@@ -3896,7 +4275,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in
show_emitter= 0;
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
show_emitter += psys->part->draw & PART_DRAW_EMITTER;
- psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy);
+ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
}
/* if no psys has "show emitter" selected don't render emitter */
@@ -3906,32 +4285,52 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in
/* one render object for the data itself */
if(allow_render) {
- obr= RE_addRenderObject(re, ob, par, index, 0);
- init_render_object_data(re, obr, only_verts);
+ obr= RE_addRenderObject(re, ob, par, index, 0, ob->lay);
+ if((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
+ obr->flag |= R_INSTANCEABLE;
+ Mat4CpyMat4(obr->obmat, ob->obmat);
+ }
+ if(obr->lay & vectorlay)
+ obr->flag |= R_NEED_VECTORS;
+ init_render_object_data(re, obr, timeoffset);
/* only add instance for objects that have not been used for dupli */
- if(!(ob->transflag & OB_RENDER_DUPLI))
- RE_addRenderInstance(re, obr, ob, par, index, 0, NULL);
+ if(!(ob->transflag & OB_RENDER_DUPLI)) {
+ obi= RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay);
+ if(dob) set_dupli_tex_mat(re, obi, dob);
+ }
+ else
+ find_dupli_instances(re, obr);
}
/* and one render object per particle system */
if(ob->particlesystem.first) {
psysindex= 1;
for(psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
- obr= RE_addRenderObject(re, ob, par, index, psysindex);
- init_render_object_data(re, obr, only_verts);
+ obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
+ if((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
+ obr->flag |= R_INSTANCEABLE;
+ Mat4CpyMat4(obr->obmat, ob->obmat);
+ }
+ if(obr->lay & vectorlay)
+ obr->flag |= R_NEED_VECTORS;
+ init_render_object_data(re, obr, timeoffset);
psys_render_restore(ob, psys);
/* only add instance for objects that have not been used for dupli */
- if(!(ob->transflag & OB_RENDER_DUPLI))
- RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL);
+ if(!(ob->transflag & OB_RENDER_DUPLI)) {
+ obi= RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay);
+ if(dob) set_dupli_tex_mat(re, obi, dob);
+ }
+ else
+ find_dupli_instances(re, obr);
}
}
}
/* par = pointer to duplicator parent, needed for object lookup table */
/* index = when duplicater copies same object (particle), the counter */
-static void init_render_object(Render *re, Object *ob, Object *par, int index, int only_verts)
+static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, int timeoffset, int vectorlay)
{
static double lasttime= 0.0;
double time;
@@ -3940,7 +4339,7 @@ static void init_render_object(Render *re, Object *ob, Object *par, int index, i
if(ob->type==OB_LAMP)
add_render_lamp(re, ob);
else if(render_object_type(ob->type))
- add_render_object(re, ob, par, index, only_verts);
+ add_render_object(re, ob, par, dob, timeoffset, vectorlay);
else {
MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
MTC_Mat4Invert(ob->imat, mat);
@@ -3965,6 +4364,14 @@ void RE_Database_Free(Render *re)
{
Object *ob = NULL;
LampRen *lar;
+
+ /* statistics for debugging render memory usage */
+ if((G.f & G_DEBUG) && (G.rendering)) {
+ if((re->r.scemode & R_PREVIEWBUTS)==0) {
+ BKE_image_print_memlist();
+ MEM_printmemlist_stats();
+ }
+ }
/* FREE */
@@ -3972,7 +4379,7 @@ void RE_Database_Free(Render *re)
freeshadowbuf(lar);
if(lar->jitter) MEM_freeN(lar->jitter);
if(lar->shadsamp) MEM_freeN(lar->shadsamp);
- if(lar->qsa) free_lamp_qmcsampler(lar);
+ if(lar->sunsky) MEM_freeN(lar->sunsky);
curvemapping_free(lar->curfalloff);
}
@@ -4010,13 +4417,14 @@ void RE_Database_Free(Render *re)
re->wrld.aotables= NULL;
re->scene->world->aotables= NULL;
}
- if((re->r.mode & R_RAYTRACE) && (re->wrld.mode & WO_AMB_OCC) &&
- (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY) && (re->qsa))
+ 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= 0;
@@ -4045,16 +4453,15 @@ static int allow_render_object(Object *ob, int nolamps, int onlyselected, Object
for(psys=ob->particlesystem.first; psys; psys=psys->next){
part=psys->part;
- if((part->draw_as==PART_DRAW_OB && part->dup_ob) || (part->draw_as==PART_DRAW_GR && part->dup_group))
- if(part->draw & PART_DRAW_EMITTER)
- allow= 1;
+ if(part->draw & PART_DRAW_EMITTER)
+ allow= 1;
}
}
if(!allow)
return 0;
}
- else if(ob->transflag & OB_DUPLI)
+ else if((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES))
return 0;
if(nolamps && (ob->type==OB_LAMP))
@@ -4066,19 +4473,128 @@ static int allow_render_object(Object *ob, int nolamps, int onlyselected, Object
return 1;
}
-static int allow_render_dupli_instance(Render *re, Object *ob, Object *obd)
+static int allow_render_dupli_instance(Render *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);
+ if(ma && (ma->mode & MA_HALO))
+ return 0;
+ }
+ }
+
+ for(psys=obd->particlesystem.first; psys; psys=psys->next)
+ if(!ELEM5(psys->part->draw_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) &&
- (!(ob->transflag & OB_DUPLIGROUP)) &&
+ (!(dob->type == OB_DUPLIGROUP) || !dob->animated) &&
!(re->r.mode & R_RADIO));
}
-static void database_init_objects(Render *re, unsigned int lay, int nolamps, int onlyselected, Object *actob, int only_verts)
+static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, int level, int enable)
+{
+ /* ugly function, but we need to set particle systems to their render
+ * settings before calling object_duplilist, to get render level duplis */
+ Group *group;
+ GroupObject *go;
+ ParticleSystem *psys;
+ DerivedMesh *dm;
+
+ if(level >= MAX_DUPLI_RECUR)
+ return;
+
+ if(ob->transflag & OB_DUPLIPARTS) {
+ for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+ if(ELEM(psys->part->draw_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ if(enable)
+ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
+ else
+ psys_render_restore(ob, psys);
+ }
+ }
+
+ if(level == 0 && enable) {
+ /* this is to make sure we get render level duplis in groups:
+ * the derivedmesh must be created before init_render_mesh,
+ * since object_duplilist does dupliparticles before that */
+ dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+ dm->release(dm);
+
+ for(psys=ob->particlesystem.first; psys; psys=psys->next)
+ psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+ }
+ }
+
+ if(ob->dup_group==NULL) return;
+ group= ob->dup_group;
+
+ for(go= group->gobject.first; go; go= go->next)
+ dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable);
+}
+
+static int get_vector_renderlayers(Scene *sce)
+{
+ SceneRenderLayer *srl;
+ int lay= 0;
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next)
+ if(srl->passflag & SCE_PASS_VECTOR)
+ lay |= srl->lay;
+
+ return lay;
+}
+
+static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int vectorlay, int level)
+{
+ GroupObject *go;
+ Object *ob;
+
+ /* 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 */
+ for(go= group->gobject.first; go; go= go->next) {
+ ob= go->ob;
+
+ if(ob->flag & OB_DONE) {
+ if(ob->transflag & OB_RENDER_DUPLI) {
+ if(allow_render_object(ob, nolamps, onlyselected, actob)) {
+ init_render_object(re, ob, NULL, 0, timeoffset, vectorlay);
+ ob->transflag &= ~OB_RENDER_DUPLI;
+
+ if(ob->dup_group)
+ add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, vectorlay, level+1);
+ }
+ }
+ }
+ }
+}
+
+static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
{
Base *base;
Object *ob;
+ Group *group;
+ ObjectInstanceRen *obi;
Scene *sce;
float mat[4][4];
+ int lay, vectorlay, redoimat= 0;
+
+ /* 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);
for(SETLOOPER(re->scene, base)) {
ob= base->object;
@@ -4092,76 +4608,149 @@ static void database_init_objects(Render *re, unsigned int lay, int nolamps, int
for(SETLOOPER(re->scene, base)) {
ob= base->object;
-
+
+ /* 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_renderlayers(sce);
+ lay= (timeoffset)? renderlay & vectorlay: renderlay;
+
/* if the object has been restricted from rendering in the outliner, ignore it */
if(ob->restrictflag & OB_RESTRICT_RENDER) continue;
/* OB_DONE means the object itself got duplicated, so was already converted */
if(ob->flag & OB_DONE) {
- if(ob->transflag & OB_RENDER_DUPLI)
- if(allow_render_object(ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, 0, only_verts);
+ /* 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(ob, nolamps, onlyselected, actob)) {
+ init_render_object(re, ob, NULL, 0, timeoffset, vectorlay);
+ ob->transflag &= ~OB_RENDER_DUPLI;
+ }
+ }
}
else if((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->scene->lay)) ) {
if((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
DupliObject *dob;
ListBase *lb;
+ redoimat= 1;
+
+ /* create list of duplis generated by this object, particle
+ * system need to have render settings set for dupli particles */
+ dupli_render_particle_set(re, ob, timeoffset, 0, 1);
lb= object_duplilist(sce, ob);
+ dupli_render_particle_set(re, ob, timeoffset, 0, 0);
+
for(dob= lb->first; dob; dob= dob->next) {
Object *obd= dob->ob;
Mat4CpyMat4(obd->obmat, dob->mat);
/* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
- if(dob->no_draw)
+ if(!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
continue;
if(obd->restrictflag & OB_RESTRICT_RENDER)
continue;
-
+
if(obd->type==OB_MBALL)
continue;
if(!allow_render_object(obd, nolamps, onlyselected, actob))
continue;
- if(allow_render_dupli_instance(re, ob, obd)) {
+ if(allow_render_dupli_instance(re, dob, obd)) {
ParticleSystem *psys;
+ ObjectRen *obr = NULL;
int psysindex;
- float imat[4][4], mat[4][4];
-
- /* compute difference between object matrix and
- * object matrix with dupli transform, in viewspace */
- Mat4Invert(imat, dob->omat);
- MTC_Mat4MulSerie(mat, re->viewmat, dob->mat, imat, re->viewinv, 0, 0, 0, 0);
-
- RE_addRenderInstance(re, NULL, obd, ob, dob->index, 0, mat);
+ float mat[4][4];
+
+ /* 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))) {
+ Mat4MulMat4(mat, dob->mat, re->viewmat);
+ obi= RE_addRenderInstance(re, NULL, obd, ob, dob->index, 0, mat, obd->lay);
+
+ /* fill in instance variables for texturing */
+ set_dupli_tex_mat(re, obi, dob);
+ if(dob->type != OB_DUPLIGROUP) {
+ VECCOPY(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);
+ if(obd->transflag & OB_RENDER_DUPLI)
+ find_dupli_instances(re, obr);
+ }
+ }
+ else
+ /* can't instance, just create the object */
+ init_render_object(re, obd, ob, dob, timeoffset, vectorlay);
+ /* 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)
- RE_addRenderInstance(re, NULL, obd, ob, dob->index, psysindex++, mat);
+ for(psys=obd->particlesystem.first; psys; psys=psys->next) {
+ if(dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, ob, psysindex))) {
+ obi= RE_addRenderInstance(re, NULL, obd, ob, dob->index, psysindex++, mat, obd->lay);
+
+ set_dupli_tex_mat(re, obi, dob);
+ if(dob->type != OB_DUPLIGROUP) {
+ VECCOPY(obi->dupliorco, dob->orco);
+ obi->dupliuv[0]= dob->uv[0];
+ obi->dupliuv[1]= dob->uv[1];
+ }
+ else {
+ assign_dupligroup_dupli(re, obi, obr);
+ if(obd->transflag & OB_RENDER_DUPLI)
+ find_dupli_instances(re, obr);
+ }
+ }
+ }
- obd->flag |= OB_DONE;
- obd->transflag |= OB_RENDER_DUPLI;
+ if(dob->type != OB_DUPLIGROUP) {
+ obd->flag |= OB_DONE;
+ obd->transflag |= OB_RENDER_DUPLI;
+ }
}
else
- init_render_object(re, obd, ob, dob->index, only_verts);
+ init_render_object(re, obd, ob, dob, timeoffset, vectorlay);
if(re->test_break()) break;
}
free_object_duplilist(lb);
if(allow_render_object(ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, 0, only_verts);
+ init_render_object(re, ob, NULL, 0, timeoffset, vectorlay);
}
else if(allow_render_object(ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, 0, only_verts);
+ init_render_object(re, ob, NULL, 0, timeoffset, vectorlay);
}
if(re->test_break()) 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= G.main->group.first; group; group=group->id.next)
+ add_group_render_dupli_obs(re, group, nolamps, onlyselected, actob, timeoffset, renderlay, 0);
+
+ /* imat objects has to be done again, since groups can mess it up */
+ if(redoimat) {
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ }
+ }
+
if(!re->test_break())
RE_makeRenderInstances(re);
}
@@ -4202,14 +4791,16 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
Mat4Ortho(re->scene->camera->obmat);
Mat4Invert(mat, re->scene->camera->obmat);
RE_SetView(re, mat);
+ re->scene->camera->recalc= OB_RECALC_OB; /* force correct matrix for scaled cameras */
}
init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if(re->wrld.mode & WO_AMB_OCC) {
- if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
- init_render_hammersley(re);
- else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ if(re->r.mode & R_RAYTRACE) {
+ init_render_qmcsampler(re);
+
+ if(re->wrld.mode & WO_AMB_OCC)
+ if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(&re->wrld);
}
/* still bad... doing all */
@@ -4270,10 +4861,17 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
if(!re->test_break())
project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
+
+ /* Occlusion */
+ if((re->wrld.mode & WO_AMB_OCC) && !re->test_break())
+ if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
+ if(re->r.renderer==R_INTERN)
+ if(re->r.mode & R_SHADOW)
+ make_occ_tree(re);
/* SSS */
if((re->r.mode & R_SSS) && !re->test_break())
- if (re->r.renderer==R_INTERN)
+ if(re->r.renderer==R_INTERN)
make_sss_tree(re);
}
@@ -4334,7 +4932,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, int timeoffset)
}
/* MAKE RENDER DATA */
- database_init_objects(re, lay, 0, 0, 0, 1);
+ database_init_objects(re, lay, 0, 0, 0, timeoffset);
if(!re->test_break())
project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
@@ -4429,14 +5027,49 @@ static void calculate_speedvector(float *vectors, int step, float winsq, float w
}
}
+static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen *obi, StrandSurface *mesh)
+{
+ float winsq= re->winx*re->winy, winroot= sqrt(winsq), (*winspeed)[4];
+ float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
+ int a;
+
+ if(mesh->co && mesh->prevco && mesh->nextco) {
+ if(obi->flag & R_TRANSFORMED)
+ Mat4MulMat4(winmat, obi->mat, re->winmat);
+ else
+ Mat4CpyMat4(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;
- float *speed, ho[4], winmat[4][4];
+ StrandBuffer *strandbuf;
+ StrandSurface *mesh= NULL;
+ float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
+ float *co1, *co2, *co3, *co4, w[4];
float winsq= re->winx*re->winy, winroot= sqrt(winsq);
- int a;
+ int a, *face, *index;
if(obi->flag & R_TRANSFORMED)
Mat4MulMat4(winmat, obi->mat, re->winmat);
@@ -4455,13 +5088,42 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
}
if(obr->strandnodes) {
- for(a=0; a<obr->totstrand; a++, vectors+=2) {
- if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
+ 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]];
+ co4= (face[3])? mesh->co[face[3]]: NULL;
+
+ InterpWeightsQ3Dfl(co1, co2, co3, co4, strand->vert->co, w);
+
+ speed[0]= speed[1]= speed[2]= speed[3]= 0.0f;
+ QUATADDFAC(speed, speed, winspeed[face[0]], w[0]);
+ QUATADDFAC(speed, speed, winspeed[face[1]], w[1]);
+ QUATADDFAC(speed, speed, winspeed[face[2]], w[2]);
+ if(face[3])
+ QUATADDFAC(speed, speed, winspeed[face[3]], w[3]);
+ }
+ }
- speed= RE_strandren_get_winspeed(obi, strand, 1);
- projectvert(strand->vert->co, winmat, ho);
- calculate_speedvector(vectors, step, winsq, winroot, strand->vert->co, ho, speed);
+ MEM_freeN(winspeed);
}
}
}
@@ -4471,36 +5133,54 @@ static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *
ObjectRen *obr= obi->obr;
Object *fsob= obr->ob;
VertRen *ver= NULL;
- float *speed, div, zco[2];
+ 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= re->winx*re->winy, winroot= sqrt(winsq);
int a, j;
float hoco[4], ho[4], fsvec[4], camco[4];
float mat[4][4], winmat[4][4];
float imat[4][4];
- MVert *vverts;
-
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsob, eModifierType_Fluidsim);
+ FluidsimSettings *fss = fluidmd->fss;
+ float *velarray = NULL;
+
/* only one step needed */
if(step) return 1;
+ if(fluidmd)
+ fss = fluidmd->fss;
+ else
+ return 0;
+
Mat4CpyMat4(mat, re->viewmat);
MTC_Mat4Invert(imat, mat);
/* set first vertex OK */
- if( (!fsob->fluidsimSettings) || (!fsob->fluidsimSettings->meshSurfNormals) ) return 0;
- vverts = fsob->fluidsimSettings->meshSurfNormals;
- //fprintf(stderr, "GZ_VEL obj '%s', calc load_fluidsimspeedvectors\n",fsob->id.name); // NT DEBUG
-
- if( obr->totvert != fsob->fluidsimSettings->meshSurface->totvert ) {
+ if(!fss->meshSurfNormals) return 0;
+
+ if( obr->totvert != GET_INT_FROM_POINTER(fss->meshSurface) ) {
//fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", obr->totvert, fsob->fluidsimSettings->meshSurface->totvert); // DEBUG
return 0;
}
+
+ velarray = (float *)fss->meshSurfNormals;
if(obi->flag & R_TRANSFORMED)
Mat4MulMat4(winmat, obi->mat, re->winmat);
else
Mat4CpyMat4(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[3*a + 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;
@@ -4510,8 +5190,16 @@ static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *
// get fluid velocity
fsvec[3] = 0.;
//fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.; fsvec[2] = 2.; // NT fixed test
- for(j=0;j<3;j++) fsvec[j] = vverts[a].co[j];
-
+ for(j=0;j<3;j++) fsvec[j] = velarray[3*a + j];
+
+ /* (bad) HACK insert average velocity if none is there (see previous comment) */
+ if((fsvec[0] == 0.0) && (fsvec[1] == 0.0) && (fsvec[2] == 0.0))
+ {
+ fsvec[0] = avgvel[0];
+ fsvec[1] = avgvel[1];
+ fsvec[2] = avgvel[2];
+ }
+
// transform (=rotate) to cam space
camco[0]= imat[0][0]*fsvec[0] + imat[0][1]*fsvec[1] + imat[0][2]*fsvec[2];
camco[1]= imat[1][0]*fsvec[0] + imat[1][1]*fsvec[1] + imat[1][2]*fsvec[2];
@@ -4552,7 +5240,6 @@ static void copy_dbase_object_vectors(Render *re, ListBase *lb)
ObjectInstanceRen *obi, *obilb;
ObjectRen *obr;
VertRen *ver= NULL;
- StrandRen *strand= NULL;
float *vec, ho[4], winmat[4][4];
int a, totvector;
@@ -4563,7 +5250,7 @@ static void copy_dbase_object_vectors(Render *re, ListBase *lb)
memcpy(obilb, obi, sizeof(ObjectInstanceRen));
BLI_addtail(lb, obilb);
- obilb->totvector= totvector= obr->totvert + obr->totstrand;
+ obilb->totvector= totvector= obr->totvert;
if(totvector > 0) {
vec= obilb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array");
@@ -4580,14 +5267,6 @@ static void copy_dbase_object_vectors(Render *re, ListBase *lb)
projectvert(ver->co, winmat, ho);
speedvector_project(NULL, vec, ver->co, ho);
}
-
- for(a=0; a<obr->totstrand; a++, vec+=2) {
- if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
-
- projectvert(strand->vert->co, winmat, ho);
- speedvector_project(NULL, vec, strand->vert->co, ho);
- }
}
}
}
@@ -4605,8 +5284,10 @@ static void free_dbase_object_vectors(ListBase *lb)
void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
{
ObjectInstanceRen *obi, *oldobi;
+ StrandSurface *mesh;
ListBase *table;
ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL};
+ ListBase strandsurface;
int step;
re->i.infostr= "Calculating previous vectors";
@@ -4621,7 +5302,10 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
copy_dbase_object_vectors(re, &oldtable);
/* free dbase and make the future one */
+ strandsurface= re->strandsurface;
+ memset(&re->strandsurface, 0, sizeof(ListBase));
RE_Database_Free(re);
+ re->strandsurface= strandsurface;
if(!re->test_break()) {
/* creates entire dbase */
@@ -4633,7 +5317,10 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
copy_dbase_object_vectors(re, &newtable);
/* free dbase and make the real one */
+ strandsurface= re->strandsurface;
+ memset(&re->strandsurface, 0, sizeof(ListBase));
RE_Database_Free(re);
+ re->strandsurface= strandsurface;
if(!re->test_break())
RE_Database_FromScene(re, sce, 1);
@@ -4647,10 +5334,14 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
table= &oldtable;
oldobi= table->first;
- for(obi= re->instancetable.first; obi && oldobi; obi= obi->next, oldobi= oldobi->next) {
+ for(obi= re->instancetable.first; obi && oldobi; obi= obi->next) {
int ok= 1;
+ FluidsimModifierData *fluidmd;
+
+ if(!(obi->obr->flag & R_NEED_VECTORS))
+ continue;
- obi->totvector= obi->obr->totvert + obi->obr->totstrand;
+ 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) {
@@ -4669,25 +5360,38 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
}
// NT check for fluidsim special treatment
- if((obi->ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (obi->ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)) {
+ 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 {
+ }
+ else {
/* check if both have same amounts of vertices */
- if(obi->totvector!=oldobi->totvector) {
+ 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);
- continue;
- }
-
- calculate_speedvectors(re, obi, oldobi->vectors, step);
} // 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->i);
@@ -4705,6 +5409,8 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
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_DISPLACEMENT:for baking, no lamps, only selected objects
+ RE_BAKE_SHADOW: for baking, only shadows, but all objects
*/
void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
{
@@ -4716,21 +5422,31 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
/* renderdata setup and exceptions */
re->r= scene->r;
- re->r.mode &= ~R_OSA;
+
+ RE_init_threadcount(re);
+
re->flag |= R_GLOB_NOPUNOFLIP;
+ re->flag |= R_BAKING;
re->excludeob= actob;
+ if(type == RE_BAKE_LIGHT)
+ re->flag |= R_SKIP_MULTIRES;
+ 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(!actob && ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE)) {
+ if(!actob && ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT)) {
re->r.mode &= ~R_SHADOW;
re->r.mode &= ~R_RAYTRACE;
}
+ if(!actob && (type==RE_BAKE_SHADOW)) {
+ re->r.mode |= R_SHADOW;
+ }
+
/* setup render stuff */
- if(type!=RE_BAKE_LIGHT)
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
re->lights.first= re->lights.last= NULL;
@@ -4752,11 +5468,12 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
}
init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if(re->wrld.mode & WO_AMB_OCC) {
- if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
- init_render_hammersley(re);
- else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ if(re->r.mode & R_RAYTRACE) {
+ init_render_qmcsampler(re);
+
+ if(re->wrld.mode & WO_AMB_OCC)
+ if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(&re->wrld);
}
/* still bad... doing all */
@@ -4765,8 +5482,8 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
set_node_shader_lamp_loop(shade_material_loop);
/* MAKE RENDER DATA */
- nolamps= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL);
- onlyselected= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE);
+ nolamps= !ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW);
+ onlyselected= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT);
database_init_objects(re, lay, nolamps, onlyselected, actob, 0);
@@ -4781,6 +5498,12 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
if(!re->test_break())
if(re->r.mode & R_RAYTRACE)
makeraytree(re);
+
+ /* occlusion */
+ if((re->wrld.mode & WO_AMB_OCC) && !re->test_break())
+ if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
+ if(re->r.mode & R_SHADOW)
+ make_occ_tree(re);
}
/* ------------------------------------------------------------------------- */
@@ -4813,7 +5536,7 @@ void RE_make_sticky(void)
}
re= RE_NewRender("_make sticky_");
- RE_InitState(re, &G.scene->r, G.scene->r.xsch, G.scene->r.ysch, NULL);
+ RE_InitState(re, NULL, &G.scene->r, G.scene->r.xsch, G.scene->r.ysch, NULL);
/* use renderdata and camera to set viewplane */
RE_SetCamera(re, G.scene->camera);
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index b1b907aebb6..13fa9b17b71 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -127,7 +127,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
envre->r.size= 100;
envre->r.yasp= envre->r.xasp= 1;
- RE_InitState(envre, &envre->r, cuberes, cuberes, NULL);
+ RE_InitState(envre, NULL, &envre->r, cuberes, cuberes, NULL);
envre->scene= re->scene; /* unsure about this... */
/* view stuff in env render */
@@ -150,14 +150,15 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
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->strandbuckets= re->strandbuckets;
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;
}
@@ -171,13 +172,14 @@ static void envmap_free_render_copy(Render *envre)
envre->totstrand= 0;
envre->totlamp= 0;
envre->totinstance= 0;
+ envre->sortedhalos= NULL;
envre->lights.first= envre->lights.last= NULL;
envre->objecttable.first= envre->objecttable.last= NULL;
- envre->strandbuckets= NULL;
envre->customdata_names.first= envre->customdata_names.last= NULL;
envre->raytree= NULL;
envre->instancetable.first= envre->instancetable.last= NULL;
envre->objectinstance= NULL;
+ envre->qmcsamplers= NULL;
RE_FreeRender(envre);
}
@@ -223,7 +225,7 @@ static void env_rotate_scene(Render *re, float mat[][4], int mode)
ObjectInstanceRen *obi;
LampRen *lar = NULL;
HaloRen *har = NULL;
- float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3];
+ float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
int a;
if(mode==0) {
@@ -237,15 +239,18 @@ static void env_rotate_scene(Render *re, float mat[][4], int mode)
for(obi=re->instancetable.first; obi; obi=obi->next) {
/* append or set matrix depending on dupli */
- if(obi->flag & R_DUPLI_TRANSFORMED)
- Mat4MulMat4(obi->mat, tmat, obi->mat);
+ if(obi->flag & R_DUPLI_TRANSFORMED) {
+ Mat4CpyMat4(tmpmat, obi->mat);
+ Mat4MulMat4(obi->mat, tmpmat, tmat);
+ }
else if(mode==1)
Mat4CpyMat4(obi->mat, tmat);
else
Mat4One(obi->mat);
Mat3CpyMat4(cmat, obi->mat);
- Mat3Inv(obi->imat, cmat);
+ Mat3Inv(obi->nmat, cmat);
+ Mat3Transp(obi->nmat);
/* indicate the renderer has to use transform matrices */
if(mode==0)
@@ -313,12 +318,13 @@ static void env_layerflags(Render *re, unsigned int notlay)
notlay= ~notlay;
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->lay & notlay)==0) {
+ for(a=0; a<obr->totvlak; a++) {
+ if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
+ else vlr++;
- if((vlr->lay & notlay)==0)
vlr->flag |= R_HIDDEN;
+ }
}
}
}
@@ -433,12 +439,19 @@ static void render_envmap(Render *re, EnvMap *env)
if(re->test_break()==0) {
RenderLayer *rl= envre->result->layers.first;
+ int y;
+ char *alpha;
ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0);
ibuf->rect_float= rl->rectf;
IMB_rect_from_float(ibuf);
ibuf->rect_float= NULL;
-
+
+ /* envmap renders without alpha */
+ alpha= ((char *)ibuf->rect)+3;
+ for(y= ibuf->x*ibuf->y - 1; y>=0; y--, alpha+=4)
+ *alpha= 255;
+
env->cube[part]= ibuf;
}
@@ -715,7 +728,7 @@ int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexRe
fac= (texres->ta+texr1.ta+texr2.ta);
if(fac!=0.0) {
fac= 1.0/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 );
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 23b5e597070..b9a2acb8b1c 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <fcntl.h>
#include <math.h>
+#include <float.h>
#ifndef WIN32
#include <unistd.h>
#else
@@ -93,10 +94,10 @@ static void ibuf_get_color(float *col, struct ImBuf *ibuf, int x, int y)
else {
char *rect = (char *)( ibuf->rect+ ofs);
- col[0] = ((float)rect[0])/255.0f;
- col[1] = ((float)rect[1])/255.0f;
- col[2] = ((float)rect[2])/255.0f;
- col[3] = ((float)rect[3])/255.0f;
+ col[0] = ((float)rect[0])*(1.0f/255.0f);
+ col[1] = ((float)rect[1])*(1.0f/255.0f);
+ col[2] = ((float)rect[2])*(1.0f/255.0f);
+ col[3] = ((float)rect[3])*(1.0f/255.0f);
}
}
@@ -245,7 +246,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, TexResult *texre
if(tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
/* de-premul, this is being premulled in shade_input_do_shade() */
- if(texres->ta!=1.0f && texres->ta!=0.0f) {
+ if(texres->ta!=1.0f && texres->ta>FLT_EPSILON) {
fx= 1.0f/texres->ta;
texres->tr*= fx;
texres->tg*= fx;
@@ -576,10 +577,10 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
if(texres->talpha==0) texres->ta= 1.0;
if(alphaclip!=1.0) {
- /* this is for later investigation, premul or not? */
- /* texres->tr*= alphaclip; */
- /* texres->tg*= alphaclip; */
- /* texres->tb*= alphaclip; */
+ /* premul it all */
+ texres->tr*= alphaclip;
+ texres->tg*= alphaclip;
+ texres->tb*= alphaclip;
texres->ta*= alphaclip;
}
}
@@ -615,6 +616,7 @@ void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *res
return;
}
+ memset(&texres, 0, sizeof(texres));
boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
result[0]= texres.tr;
result[1]= texres.tg;
@@ -699,10 +701,22 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
maxy= MAX3(dxt[1],dyt[1],dxt[1]+dyt[1] );
/* tex_sharper has been removed */
- minx= tex->filtersize*(maxx-minx)/2.0f;
- miny= tex->filtersize*(maxy-miny)/2.0f;
+ minx= (maxx-minx)/2.0f;
+ miny= (maxy-miny)/2.0f;
- if(tex->filtersize!=1.0f) {
+ if(tex->imaflag & TEX_FILTER_MIN) {
+ /* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
+ float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y);
+
+ if(addval > minx)
+ minx= addval;
+ if(addval > miny)
+ miny= addval;
+ }
+ else if(tex->filtersize!=1.0f) {
+ minx*= tex->filtersize;
+ miny*= tex->filtersize;
+
dxt[0]*= tex->filtersize;
dxt[1]*= tex->filtersize;
dyt[0]*= tex->filtersize;
@@ -977,7 +991,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
}
/* de-premul, this is being premulled in shade_input_do_shade() */
- if(texres->ta!=1.0f && texres->ta!=0.0f) {
+ if(texres->ta!=1.0f && texres->ta>FLT_EPSILON) {
fx= 1.0f/texres->ta;
texres->tr*= fx;
texres->tg*= fx;
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 3ea8c6edffa..40c0edb6e5f 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -257,7 +257,7 @@ void make_sample_tables(Render *re)
{
static int firsttime= 1;
SampleTables *st;
- float flweight[32], fmask[256];
+ float flweight[32];
float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
int i, j, a;
@@ -300,11 +300,6 @@ void make_sample_tables(Render *re)
st->centLut[a]= -0.45+((float)a)/16.0;
}
- val= 1.0/((float)re->osa);
- for(a=0; a<256; a++) {
- fmask[a]= ((float)st->cmask[a])*val;
- }
-
/* calculate totw */
totw= 0.0;
for(j= -1; j<2; j++) {
@@ -459,7 +454,10 @@ void RE_SetCamera(Render *re, Object *camera)
if(cam->type==CAM_ORTHO) re->r.mode |= R_ORTHO;
- /* solve this too... all time depending stuff is in convertblender.c? */
+ /* solve this too... all time depending stuff is in convertblender.c?
+ * Need to update the camera early because it's used for projection matrices
+ * and other stuff BEFORE the animation update loop is done
+ * */
if(cam->ipo) {
calc_ipo(cam->ipo, frame_to_float(re->r.cfra));
execute_ipo(&cam->id, cam->ipo);
@@ -603,24 +601,20 @@ void initparts(Render *re)
/* mininum part size, but for exr tile saving it was checked already */
if(!(re->r.scemode & R_EXR_TILE_FILE)) {
if(re->r.mode & R_PANORAMA) {
- if(re->rectx/xparts < 8)
+ if(ceil(re->rectx/(float)xparts) < 8)
xparts= 1 + re->rectx/8;
}
else
- if(re->rectx/xparts < 64)
+ if(ceil(re->rectx/(float)xparts) < 64)
xparts= 1 + re->rectx/64;
- if(re->recty/yparts < 64)
+ if(ceil(re->recty/(float)yparts) < 64)
yparts= 1 + re->recty/64;
}
/* part size */
- partx= re->rectx/xparts;
- party= re->recty/yparts;
-
- /* if remainder pixel, add one, then parts are more equal in size for large panoramas */
- if(re->rectx % partx)
- partx++;
+ partx= ceil(re->rectx/(float)xparts);
+ party= ceil(re->recty/(float)yparts);
re->xparts= xparts;
re->yparts= yparts;
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
new file mode 100644
index 00000000000..d2d2cf3fb77
--- /dev/null
+++ b/source/blender/render/intern/source/occlusion.c
@@ -0,0 +1,1763 @@
+/*
+ * $Id$
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_memarena.h"
+#include "BLI_threads.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#include "RE_shader_ext.h"
+
+/* local includes */
+#include "occlusion.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "pixelshading.h"
+#include "shading.h"
+#include "zbuf.h"
+
+/* ------------------------- Declarations --------------------------- */
+
+#define INVALID_INDEX ((int)(~0))
+#define INVPI 0.31830988618379069f
+#define TOTCHILD 8
+#define CACHE_STEP 3
+
+typedef struct OcclusionCacheSample {
+ float co[3], n[3], col[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;
+ 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 */
+
+ OccNode *root;
+
+ OccNode **stack[BLENDER_MAX_THREADS];
+ int maxdepth;
+
+ int totface;
+
+ float error;
+ float distfac;
+
+ int dothreadedbuild;
+ int totbuildthread;
+
+ OcclusionCache *cache;
+} OcclusionTree;
+
+typedef struct OcclusionThread {
+ Render *re;
+ StrandSurface *mesh;
+ float (*facecol)[3];
+ int begin, end;
+ int thread;
+} OcclusionThread;
+
+typedef struct OcclusionBuildThread {
+ OcclusionTree *tree;
+ int begin, end, depth;
+ OccNode *node;
+} OcclusionBuildThread;
+
+/* ------------------------- Shading --------------------------- */
+
+extern Render R; // meh
+
+#if 0
+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 */
+ VECCOPY(shi->view, shi->co);
+ Normalize(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);
+
+ /* not a pretty solution, but fixes common cases */
+ if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
+ VecMulf(shi->vn, -1.0f);
+ VecMulf(shi->vno, -1.0f);
+ }
+
+ /* init material vars */
+ // note, keep this synced with render_types.h
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ /* render */
+ shade_input_set_shade_texco(shi);
+ shade_material_loop(shi, shr); /* todo: nodes */
+
+ VECCOPY(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->scene->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].vlr);
+
+ occ_shade(&ssamp, obi, vlr, tree->rad[a]);
+ }
+}
+#endif
+
+/* ------------------------- 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, float *normal, 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)
+ VecLerpf(co, vlr->v1->co, vlr->v3->co, 0.5f);
+ else
+ CalcCent3f(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+
+ if(obi->flag & R_TRANSFORMED)
+ Mat4MulVecfl(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)
+ Mat3MulVecfl(obi->nmat, normal);
+ }
+
+ if(area) {
+ VECCOPY(v1, vlr->v1->co);
+ VECCOPY(v2, vlr->v2->co);
+ VECCOPY(v3, vlr->v3->co);
+ if(vlr->v4) VECCOPY(v4, vlr->v4->co);
+
+ if(obi->flag & R_TRANSFORMED) {
+ Mat4MulVecfl(obi->mat, v1);
+ Mat4MulVecfl(obi->mat, v2);
+ Mat4MulVecfl(obi->mat, v3);
+ if(vlr->v4) Mat4MulVecfl(obi->mat, v4);
+ }
+
+ /* todo: correct area for instances */
+ if(vlr->v4)
+ *area= AreaQ3Dfl(v1, v2, v3, v4);
+ else
+ *area= AreaT3Dfl(v1, v2, v3);
+ }
+}
+
+static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node)
+{
+ OccNode *child;
+ float occ, area, totarea;
+ int a, b;
+
+ occ= 0.0f;
+ totarea= 0.0f;
+
+ for(b=0; b<TOTCHILD; b++) {
+ if(node->childflag & (1<<b)) {
+ a= node->child[b].face;
+ occ_face(&tree->face[a], 0, 0, &area);
+ occ += area*tree->occlusion[a];
+ totarea += area;
+ }
+ else if(node->child[b].node) {
+ child= node->child[b].node;
+ occ_sum_occlusion(tree, child);
+
+ occ += child->area*child->occlusion;
+ totarea += child->area;
+ }
+ }
+
+ if(totarea != 0.0f)
+ occ /= totarea;
+
+ node->occlusion= occ;
+}
+
+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++)
+ DO_MINMAX(tree->co[a], min, max)
+
+ 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, float *co, float *dco)
+{
+ OccNode *child;
+ float dist, d[3], nco[3];
+ int b;
+
+ for(b=0; b<TOTCHILD; b++) {
+ if(node->childflag & (1<<b)) {
+ occ_face(tree->face+node->child[b].face, nco, 0, 0);
+ }
+ else if(node->child[b].node) {
+ child= node->child[b].node;
+ occ_build_dco(tree, child, co, dco);
+ VECCOPY(nco, child->co);
+ }
+
+ VECSUB(d, nco, co);
+ dist= INPR(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(float, tree->co[a][0], tree->co[enda][0]);
+ SWAP(float, tree->co[a][1], tree->co[enda][1]);
+ SWAP(float, tree->co[a][2], tree->co[enda][2]);
+ }
+ 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 0;
+}
+
+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];
+
+ /* keep track of maximum depth for stack */
+ if(depth > tree->maxdepth)
+ tree->maxdepth= depth;
+
+ /* 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_init_threads(&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_lock_thread(LOCK_CUSTOM1);
+
+ child= BLI_memarena_alloc(tree->arena, sizeof(OccNode));
+ node->child[b].node= child;
+
+ if(tree->dothreadedbuild)
+ BLI_unlock_thread(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_insert_thread(&threads, &othreads[totthread]);
+ totthread++;
+ }
+ else
+ occ_build_recursive(tree, child, offset[b], offset[b]+count[b], depth+1);
+ }
+ }
+
+ if(depth == 1 && tree->dothreadedbuild)
+ BLI_end_threads(&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);
+ VECADDFAC(node->co, node->co, child->co, child->area);
+ }
+ }
+
+ if(node->area != 0.0f)
+ VecMulf(node->co, 1.0f/node->area);
+
+ /* compute maximum distance from center */
+ node->dco= 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 mutliply 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));
+ else if(node->child[b].node)
+ occ_build_sh_normalize(node->child[b].node);
+ }
+}
+
+static OcclusionTree *occ_tree_build(Render *re)
+{
+ OcclusionTree *tree;
+ ObjectInstanceRen *obi;
+ ObjectRen *obr;
+ 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++;
+
+ if(vlr->mat->mode & MA_TRACEBLE)
+ 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;
+
+ /* allocation */
+ tree->arena= BLI_memarena_new(0x8000 * sizeof(OccNode));
+ BLI_memarena_use_calloc(tree->arena);
+
+ if(re->wrld.aomode & WO_AOCACHE)
+ tree->cache= MEM_callocN(sizeof(OcclusionCache)*BLENDER_MAX_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");
+
+ /* 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++;
+
+ if(vlr->mat->mode & MA_TRACEBLE) {
+ 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));
+ occ_build_recursive(tree, tree->root, 0, totface, 1);
+
+#if 0
+ if(tree->doindirect) {
+ occ_build_shade(re, tree);
+ occ_sum_occlusion(tree, tree->root);
+ }
+#endif
+
+ MEM_freeN(tree->co);
+ tree->co= NULL;
+
+ occ_build_sh_normalize(tree->root);
+
+ for(a=0; a<BLENDER_MAX_THREADS; a++)
+ tree->stack[a]= MEM_callocN(sizeof(OccNode)*TOTCHILD*(tree->maxdepth+1), "OccStack");
+
+ 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<BLENDER_MAX_THREADS; a++)
+ if(tree->stack[a])
+ MEM_freeN(tree->stack[a]);
+ if(tree->occlusion) MEM_freeN(tree->occlusion);
+ if(tree->face) MEM_freeN(tree->face);
+ if(tree->cache) MEM_freeN(tree->cache);
+ MEM_freeN(tree);
+ }
+}
+
+/* ------------------------- Traversal --------------------------- */
+
+static float occ_solid_angle(OccNode *node, float *v, float d2, float invd2, float *receivenormal)
+{
+ 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= INPR(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 void VecAddDir(float *result, float *v1, float *v2, float fac)
+{
+ result[0]= v1[0] + fac*(v2[0] - v1[0]);
+ result[1]= v1[1] + fac*(v2[1] - v1[1]);
+ result[2]= v1[2] + fac*(v2[2] - v1[2]);
+}
+
+static int occ_visible_quad(float *p, float *n, float *v0, float *v1, float *v2, float *q0, float *q1, float *q2, float *q3)
+{
+ static const float epsilon = 1e-6f;
+ float c, sd[3];
+
+ c= INPR(n, p);
+
+ /* signed distances from the vertices to the plane. */
+ sd[0]= INPR(n, v0) - c;
+ sd[1]= INPR(n, v1) - c;
+ sd[2]= INPR(n, v2) - c;
+
+ if(fabs(sd[0]) < epsilon) sd[0] = 0.0f;
+ if(fabs(sd[1]) < epsilon) sd[1] = 0.0f;
+ if(fabs(sd[2]) < epsilon) sd[2] = 0.0f;
+
+ if(sd[0] > 0) {
+ if(sd[1] > 0) {
+ if(sd[2] > 0) {
+ // +++
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // ++-
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VecAddDir(q3, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ }
+ else {
+ // ++0
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ }
+ else if(sd[1] < 0) {
+ if(sd[2] > 0) {
+ // +-+
+ VECCOPY(q0, v0);
+ VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VECCOPY(q3, v2);
+ }
+ else if(sd[2] < 0) {
+ // +--
+ VECCOPY(q0, v0);
+ VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VecAddDir(q2, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ VECCOPY(q3, q2);
+ }
+ else {
+ // +-0
+ VECCOPY(q0, v0);
+ VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ }
+ else {
+ if(sd[2] > 0) {
+ // +0+
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // +0-
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VecAddDir(q2, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ VECCOPY(q3, q2);
+ }
+ else {
+ // +00
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ }
+ }
+ else if(sd[0] < 0) {
+ if(sd[1] > 0) {
+ if(sd[2] > 0) {
+ // -++
+ VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VecAddDir(q3, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ }
+ else if(sd[2] < 0) {
+ // -+-
+ VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VECCOPY(q1, v1);
+ VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VECCOPY(q3, q2);
+ }
+ else {
+ // -+0
+ VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1])));
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ }
+ else if(sd[1] < 0) {
+ if(sd[2] > 0) {
+ // --+
+ VecAddDir(q0, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ VecAddDir(q1, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // ---
+ return 0;
+ }
+ else {
+ // --0
+ return 0;
+ }
+ }
+ else {
+ if(sd[2] > 0) {
+ // -0+
+ VecAddDir(q0, v0, v2, (sd[0]/(sd[0]-sd[2])));
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // -0-
+ return 0;
+ }
+ else {
+ // -00
+ return 0;
+ }
+ }
+ }
+ else {
+ if(sd[1] > 0) {
+ if(sd[2] > 0) {
+ // 0++
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // 0+-
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VECCOPY(q3, q2);
+ }
+ else {
+ // 0+0
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ }
+ else if(sd[1] < 0) {
+ if(sd[2] > 0) {
+ // 0-+
+ VECCOPY(q0, v0);
+ VecAddDir(q1, v1, v2, (sd[1]/(sd[1]-sd[2])));
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // 0--
+ return 0;
+ }
+ else {
+ // 0-0
+ return 0;
+ }
+ }
+ else {
+ if(sd[2] > 0) {
+ // 00+
+ VECCOPY(q0, v0);
+ VECCOPY(q1, v1);
+ VECCOPY(q2, v2);
+ VECCOPY(q3, q2);
+ }
+ else if(sd[2] < 0) {
+ // 00-
+ return 0;
+ }
+ else {
+ // 000
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* altivec optimization, this works, but is unused */
+
+#if 0
+#include <Accelerate/Accelerate.h>
+
+typedef union {
+ vFloat v;
+ float f[4];
+} vFloatResult;
+
+static vFloat vec_splat_float(float val)
+{
+ return (vFloat){val, val, val, val};
+}
+
+static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
+{
+ vFloat vcos, rlen, vrx, vry, vrz, vsrx, vsry, vsrz, gx, gy, gz, vangle;
+ vUInt8 rotate = (vUInt8){4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3};
+ vFloatResult vresult;
+ float result;
+
+ /* compute r* */
+ vrx = (vFloat){q0[0], q1[0], q2[0], q3[0]} - vec_splat_float(p[0]);
+ vry = (vFloat){q0[1], q1[1], q2[1], q3[1]} - vec_splat_float(p[1]);
+ vrz = (vFloat){q0[2], q1[2], q2[2], q3[2]} - vec_splat_float(p[2]);
+
+ /* normalize r* */
+ rlen = vec_rsqrte(vrx*vrx + vry*vry + vrz*vrz + vec_splat_float(1e-16f));
+ vrx = vrx*rlen;
+ vry = vry*rlen;
+ vrz = vrz*rlen;
+
+ /* rotate r* for cross and dot */
+ vsrx= vec_perm(vrx, vrx, rotate);
+ vsry= vec_perm(vry, vry, rotate);
+ vsrz= vec_perm(vrz, vrz, rotate);
+
+ /* cross product */
+ gx = vsry*vrz - vsrz*vry;
+ gy = vsrz*vrx - vsrx*vrz;
+ gz = vsrx*vry - vsry*vrx;
+
+ /* normalize */
+ rlen = vec_rsqrte(gx*gx + gy*gy + gz*gz + vec_splat_float(1e-16f));
+ gx = gx*rlen;
+ gy = gy*rlen;
+ gz = gz*rlen;
+
+ /* angle */
+ vcos = vrx*vsrx + vry*vsry + vrz*vsrz;
+ vcos= vec_max(vec_min(vcos, vec_splat_float(1.0f)), vec_splat_float(-1.0f));
+ vangle= vacosf(vcos);
+
+ /* dot */
+ vresult.v = (vec_splat_float(n[0])*gx +
+ vec_splat_float(n[1])*gy +
+ vec_splat_float(n[2])*gz)*vangle;
+
+ result= (vresult.f[0] + vresult.f[1] + vresult.f[2] + vresult.f[3])*(0.5f/(float)M_PI);
+ result= MAX2(result, 0.0f);
+
+ return result;
+}
+
+#endif
+
+/* SSE optimization, acos code doesn't work */
+
+#if 0
+
+#include <xmmintrin.h>
+
+static __m128 sse_approx_acos(__m128 x)
+{
+ /* needs a better approximation than taylor expansion of acos, since that
+ * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work
+ * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */
+
+ return _mm_set_ps1(1.0f);
+}
+
+static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
+{
+ float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
+ float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
+ float fresult[4] __attribute__((aligned(16)));
+ __m128 qx, qy, qz, rx, ry, rz, rlen, srx, sry, srz, gx, gy, gz, glen, rcos, angle, aresult;
+
+ /* compute r */
+ qx = _mm_set_ps(q3[0], q2[0], q1[0], q0[0]);
+ qy = _mm_set_ps(q3[1], q2[1], q1[1], q0[1]);
+ qz = _mm_set_ps(q3[2], q2[2], q1[2], q0[2]);
+
+ rx = qx - _mm_set_ps1(p[0]);
+ ry = qy - _mm_set_ps1(p[1]);
+ rz = qz - _mm_set_ps1(p[2]);
+
+ /* normalize r */
+ rlen = _mm_rsqrt_ps(rx*rx + ry*ry + rz*rz + _mm_set_ps1(1e-16f));
+ rx = rx*rlen;
+ ry = ry*rlen;
+ rz = rz*rlen;
+
+ /* cross product */
+ srx = _mm_shuffle_ps(rx, rx, _MM_SHUFFLE(0,3,2,1));
+ sry = _mm_shuffle_ps(ry, ry, _MM_SHUFFLE(0,3,2,1));
+ srz = _mm_shuffle_ps(rz, rz, _MM_SHUFFLE(0,3,2,1));
+
+ gx = sry*rz - srz*ry;
+ gy = srz*rx - srx*rz;
+ gz = srx*ry - sry*rx;
+
+ /* normalize g */
+ glen = _mm_rsqrt_ps(gx*gx + gy*gy + gz*gz + _mm_set_ps1(1e-16f));
+ gx = gx*glen;
+ gy = gy*glen;
+ gz = gz*glen;
+
+ /* compute angle */
+ rcos = rx*srx + ry*sry + rz*srz;
+ rcos= _mm_max_ps(_mm_min_ps(rcos, _mm_set_ps1(1.0f)), _mm_set_ps1(-1.0f));
+
+ angle = sse_approx_cos(rcos);
+ aresult = (_mm_set_ps1(n[0])*gx + _mm_set_ps1(n[1])*gy + _mm_set_ps1(n[2])*gz)*angle;
+
+ /* sum together */
+ result= (fresult[0] + fresult[1] + fresult[2] + fresult[3])*(0.5f/(float)M_PI);
+ result= MAX2(result, 0.0f);
+
+ return result;
+}
+
+#endif
+
+static float saacosf(float fac)
+{
+ if(fac<= -1.0f) return (float)M_PI;
+ else if(fac>=1.0f) return 0.0f;
+ else return acos(fac); /* acosf(fac) */
+}
+
+static void normalizef(float *n)
+{
+ float d;
+
+ d= INPR(n, n);
+
+ if(d > 1.0e-35F) {
+ d= 1.0f/sqrt(d); /* sqrtf(d) */
+
+ n[0] *= d;
+ n[1] *= d;
+ n[2] *= d;
+ }
+}
+
+static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
+{
+ float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
+ float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
+
+ VECSUB(r0, q0, p);
+ VECSUB(r1, q1, p);
+ VECSUB(r2, q2, p);
+ VECSUB(r3, q3, p);
+
+ normalizef(r0);
+ normalizef(r1);
+ normalizef(r2);
+ normalizef(r3);
+
+ Crossf(g0, r1, r0); normalizef(g0);
+ Crossf(g1, r2, r1); normalizef(g1);
+ Crossf(g2, r3, r2); normalizef(g2);
+ Crossf(g3, r0, r3); normalizef(g3);
+
+ a1= saacosf(INPR(r0, r1));
+ a2= saacosf(INPR(r1, r2));
+ a3= saacosf(INPR(r2, r3));
+ a4= saacosf(INPR(r3, r0));
+
+ dot1= INPR(n, g0);
+ dot2= INPR(n, g1);
+ dot3= INPR(n, g2);
+ dot4= INPR(n, g3);
+
+ result= (a1*dot1 + a2*dot2 + a3*dot3 + a4*dot4)*0.5f/(float)M_PI;
+ result= MAX2(result, 0.0f);
+
+ return result;
+}
+
+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);
+
+ VECCOPY(v1, vlr->v1->co);
+ VECCOPY(v2, vlr->v2->co);
+ VECCOPY(v3, vlr->v3->co);
+
+ if(obi->flag & R_TRANSFORMED) {
+ Mat4MulVecfl(obi->mat, v1);
+ Mat4MulVecfl(obi->mat, v2);
+ Mat4MulVecfl(obi->mat, v3);
+ }
+
+ if(occ_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+
+ if(vlr->v4) {
+ VECCOPY(v4, vlr->v4->co);
+ if(obi->flag & R_TRANSFORMED)
+ Mat4MulVecfl(obi->mat, v4);
+
+ if(occ_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+ }
+
+ return contrib;
+}
+
+static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float *pp, float *pn, float *occ, float *bentn)
+{
+ OccNode *node, **stack;
+ OccFace *face;
+ float resultocc, v[3], p[3], n[3], co[3], invd2;
+ float distfac, fac, error, d2, weight, emitarea;
+ int b, totstack;
+
+ /* init variables */
+ VECCOPY(p, pp);
+ VECCOPY(n, pn);
+ VECADDFAC(p, p, n, 1e-4f);
+
+ if(bentn)
+ VECCOPY(bentn, n);
+
+ error= tree->error;
+ distfac= tree->distfac;
+
+ resultocc= 0.0f;
+
+ /* init stack */
+ stack= tree->stack[thread];
+ stack[0]= tree->root;
+ totstack= 1;
+
+ while(totstack) {
+ /* pop point off the stack */
+ node= stack[--totstack];
+
+ VECSUB(v, node->co, p);
+ d2= INPR(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/sqrt(d2);
+ weight= occ_solid_angle(node, v, d2, invd2, n);
+ 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)) {
+ face= tree->face+node->child[b].face;
+
+ /* 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);
+ VECSUB(v, co, p);
+ d2= INPR(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);
+ weight *= tree->occlusion[node->child[b].face];
+
+ if(bentn) {
+ invd2= 1.0f/sqrt(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(bentn) Normalize(bentn);
+}
+
+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);
+ VecMulf(n, -1.0f);
+ VECADDFAC(co, co, n, 1e-8f);
+
+ occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL);
+ if(re->test_break())
+ break;
+ }
+
+ if(re->test_break())
+ 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, float *co, float *n, int thread, int onlyshadow, float *skycol)
+{
+ float nn[3], bn[3], fac, occ, occlusion, correction;
+ int aocolor;
+
+ aocolor= re->wrld.aocolor;
+ if(onlyshadow)
+ aocolor= WO_AOPLAIN;
+
+ VECCOPY(nn, n);
+ VecMulf(nn, -1.0f);
+
+ occ_lookup(tree, thread, exclude, co, nn, &occ, (aocolor)? 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*exp(-occ);
+
+ if(aocolor) {
+ /* sky shading using bent normal */
+ if(ELEM(aocolor, WO_AOSKYCOL, WO_AOSKYTEX)) {
+ fac= 0.5*(1.0f+bn[0]*re->grvec[0]+ bn[1]*re->grvec[1]+ bn[2]*re->grvec[2]);
+ skycol[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr;
+ skycol[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng;
+ skycol[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb;
+ }
+#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(skycol, co, bn, dxyview);
+ }
+#endif
+
+ VecMulf(skycol, occlusion);
+ }
+ else {
+ skycol[0]= occlusion;
+ skycol[1]= occlusion;
+ skycol[2]= occlusion;
+ }
+}
+
+/* ---------------------------- 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 *col)
+{
+ 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) {
+ VECSUB(d, sample->co, co);
+ dist2= INPR(d, d);
+ if(dist2 < 0.5f*sample->dist2 && INPR(sample->n, n) > 0.98f) {
+ VECCOPY(col, sample->col);
+ return 1;
+ }
+ }
+ }
+ else
+ return 0;
+
+ /* try to interpolate between 4 neighbouring 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= MIN4(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
+ maxo= MAX4(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
+
+ if(maxo - mino > 0.05f)
+ return 0;
+
+ /* compute weighted interpolation between samples */
+ col[0]= col[1]= col[2]= 0.0f;
+ 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++) {
+ VECSUB(d, samples[i]->co, co);
+ dist2= INPR(d, d);
+
+ wz[i]= 1.0f; //(samples[i]->dist2/(1e-4f + dist2));
+ wn[i]= pow(INPR(samples[i]->n, n), 32.0f);
+
+ w= wb[i]*wn[i]*wz[i];
+
+ totw += w;
+ col[0] += w*samples[i]->col[0];
+ col[1] += w*samples[i]->col[1];
+ col[2] += w*samples[i]->col[2];
+ }
+
+ if(totw >= 0.9f) {
+ totw= 1.0f/totw;
+ col[0] *= totw;
+ col[1] *= totw;
+ col[2] *= totw;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void sample_occ_surface(ShadeInput *shi)
+{
+ StrandRen *strand= shi->strand;
+ StrandSurface *mesh= strand->buffer->surface;
+ 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->col && index) {
+ face= mesh->face[*index];
+
+ co1= mesh->co[face[0]];
+ co2= mesh->co[face[1]];
+ co3= mesh->co[face[2]];
+ co4= (face[3])? mesh->co[face[3]]: NULL;
+
+ InterpWeightsQ3Dfl(co1, co2, co3, co4, strand->vert->co, w);
+
+ shi->ao[0]= shi->ao[1]= shi->ao[2]= 0.0f;
+ VECADDFAC(shi->ao, shi->ao, mesh->col[face[0]], w[0]);
+ VECADDFAC(shi->ao, shi->ao, mesh->col[face[1]], w[1]);
+ VECADDFAC(shi->ao, shi->ao, mesh->col[face[2]], w[2]);
+ if(face[3])
+ VECADDFAC(shi->ao, shi->ao, mesh->col[face[3]], w[3]);
+ }
+ else {
+ shi->ao[0]= 1.0f;
+ shi->ao[1]= 1.0f;
+ shi->ao[2]= 1.0f;
+ }
+}
+
+/* ------------------------- External Functions --------------------------- */
+
+static void *exec_strandsurface_sample(void *data)
+{
+ OcclusionThread *othread= (OcclusionThread*)data;
+ Render *re= othread->re;
+ StrandSurface *mesh= othread->mesh;
+ float col[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]];
+
+ VecLerpf(co, co1, co3, 0.5f);
+ CalcNormFloat4(co1, co2, co3, co4, n);
+ }
+ else {
+ CalcCent3f(co, co1, co2, co3);
+ CalcNormFloat(co1, co2, co3, n);
+ }
+ VecMulf(n, -1.0f);
+
+ sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, col);
+ VECCOPY(othread->facecol[a], col);
+ }
+
+ return 0;
+}
+
+void make_occ_tree(Render *re)
+{
+ OcclusionThread othreads[BLENDER_MAX_THREADS];
+ StrandSurface *mesh;
+ ListBase threads;
+ float col[3], (*facecol)[3];
+ int a, totface, totthread, *face, *count;
+
+ /* ugly, needed for occ_face */
+ R= *re;
+
+ re->i.infostr= "Occlusion preprocessing";
+ re->stats_draw(&re->i);
+
+ re->occlusiontree= occ_tree_build(re);
+
+ if(re->occlusiontree) {
+ if(re->wrld.ao_approx_passes)
+ occ_compute_passes(re, re->occlusiontree, re->wrld.ao_approx_passes);
+
+ for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
+ if(!mesh->face || !mesh->co || !mesh->col)
+ continue;
+
+ count= MEM_callocN(sizeof(int)*mesh->totvert, "OcclusionCount");
+ facecol= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceCol");
+
+ totthread= (mesh->totface > 10000)? re->r.threads: 1;
+ totface= mesh->totface/totthread;
+ for(a=0; a<totthread; a++) {
+ othreads[a].re= re;
+ othreads[a].facecol= facecol;
+ 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_init_threads(&threads, exec_strandsurface_sample, totthread);
+
+ for(a=0; a<totthread; a++)
+ BLI_insert_thread(&threads, &othreads[a]);
+
+ BLI_end_threads(&threads);
+ }
+
+ for(a=0; a<mesh->totface; a++) {
+ face= mesh->face[a];
+
+ VECCOPY(col, facecol[a]);
+ VECADD(mesh->col[face[0]], mesh->col[face[0]], col);
+ count[face[0]]++;
+ VECADD(mesh->col[face[1]], mesh->col[face[1]], col);
+ count[face[1]]++;
+ VECADD(mesh->col[face[2]], mesh->col[face[2]], col);
+ count[face[2]]++;
+
+ if(face[3]) {
+ VECADD(mesh->col[face[3]], mesh->col[face[3]], col);
+ count[face[3]]++;
+ }
+ }
+
+ for(a=0; a<mesh->totvert; a++)
+ if(count[a])
+ VecMulf(mesh->col[a], 1.0f/count[a]);
+
+ MEM_freeN(count);
+ MEM_freeN(facecol);
+ }
+ }
+}
+
+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(!sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao)) {
+ /* 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);
+
+ /* 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)];
+ VECCOPY(sample->co, shi->co);
+ VECCOPY(sample->n, shi->vno);
+ VECCOPY(sample->col, shi->ao);
+ sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]);
+ sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco);
+ sample->filled= 1;
+ }
+ }
+ }
+ }
+ else {
+ shi->ao[0]= 1.0f;
+ shi->ao[1]= 1.0f;
+ shi->ao[2]= 1.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);
+
+ VECCOPY(sample->co, shi->co);
+ VECCOPY(sample->n, shi->vno);
+ VECCOPY(sample->col, shi->ao);
+ sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]);
+ sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco);
+ sample->x= shi->xs;
+ sample->y= shi->ys;
+ sample->filled= 1;
+ }
+
+ if(re->test_break())
+ 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 5315552310a..2d7d954b70d 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -38,6 +38,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_utildefines.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -76,6 +77,7 @@
#include "envmap.h"
#include "initrender.h"
#include "shadbuf.h"
+#include "pixelblending.h"
#include "zbuf.h"
@@ -114,7 +116,7 @@ static struct ListBase RenderList= {NULL, NULL};
Render R;
/* commandline thread override */
-static int commandline_threads= 0;
+static int commandline_threads= -1;
/* ********* alloc and free ******** */
@@ -135,30 +137,27 @@ static void print_error(char *str) {printf("ERROR: %s\n", str);}
static void stats_background(RenderStats *rs)
{
- extern unsigned long mem_in_use;
+ uintptr_t mem_in_use= MEM_get_memory_in_use();
float megs_used_memory= mem_in_use/(1024.0*1024.0);
char str[400], *spos= str;
- if(rs->convertdone) {
-
- spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", G.scene->r.cfra, megs_used_memory);
-
- if(rs->curfield)
- spos+= sprintf(spos, "Field %d ", rs->curfield);
- if(rs->curblur)
- spos+= sprintf(spos, "Blur %d ", rs->curblur);
-
- if(rs->infostr) {
- spos+= sprintf(spos, "| %s", rs->infostr);
- }
- else {
- if(rs->tothalo)
- spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d Ha:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->tothalo, rs->totlamp);
- else
- spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
- }
- printf(str); printf("\n");
- }
+ spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", G.scene->r.cfra, megs_used_memory);
+
+ if(rs->curfield)
+ spos+= sprintf(spos, "Field %d ", rs->curfield);
+ if(rs->curblur)
+ spos+= sprintf(spos, "Blur %d ", rs->curblur);
+
+ if(rs->infostr) {
+ spos+= sprintf(spos, "| %s", rs->infostr);
+ }
+ else {
+ if(rs->tothalo)
+ spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d Ha:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->tothalo, rs->totlamp);
+ else
+ spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
+ }
+ printf(str); printf("\n");
}
void RE_FreeRenderResult(RenderResult *res)
@@ -193,6 +192,22 @@ void RE_FreeRenderResult(RenderResult *res)
MEM_freeN(res);
}
+/* version that's compatible with fullsample buffers */
+static void free_render_result(ListBase *lb, RenderResult *rr)
+{
+ RenderResult *rrnext;
+
+ for(; rr; rr= rrnext) {
+ rrnext= rr->next;
+
+ if(lb && lb->first)
+ BLI_remlink(lb, rr);
+
+ RE_FreeRenderResult(rr);
+ }
+}
+
+
/* all layers except the active one get temporally pushed away */
static void push_render_result(Render *re)
{
@@ -329,6 +344,10 @@ static char *get_pass_name(int passtype, int channel)
if(channel==-1) return "IndexOB";
return "IndexOB.X";
}
+ if(passtype == SCE_PASS_MIST) {
+ if(channel==-1) return "Mist";
+ return "Mist.Z";
+ }
return "Unknown";
}
@@ -377,23 +396,25 @@ static int passtype_from_name(char *str)
if(strcmp(str, "IndexOB")==0)
return SCE_PASS_INDEXOB;
+ if(strcmp(str, "Mist")==0)
+ return SCE_PASS_MIST;
+
return 0;
}
-
-
-static void render_unique_exr_name(Render *re, char *str)
+static void render_unique_exr_name(Render *re, char *str, int sample)
{
char di[FILE_MAX], name[FILE_MAXFILE], fi[FILE_MAXFILE];
BLI_strncpy(di, G.sce, FILE_MAX);
BLI_splitdirstring(di, fi);
- sprintf(name, "%s_%s.exr", fi, re->scene->id.name+2);
- if(G.background)
- BLI_make_file_string("/", str, "/tmp/", name);
+
+ if(sample==0)
+ sprintf(name, "%s_%s.exr", fi, re->scene->id.name+2);
else
- BLI_make_file_string("/", str, U.tempdir, name);
-
+ sprintf(name, "%s_%s%d.exr", fi, re->scene->id.name+2, sample);
+
+ BLI_make_file_string("/", str, btempdir, name);
}
static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
@@ -412,17 +433,22 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel
IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
}
else {
+ float *rect;
+ int x;
+
+ rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
+
if(passtype==SCE_PASS_VECTOR) {
- float *rect;
- int x;
-
/* initialize to max speed */
- rect= rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
+ rect= rpass->rect;
for(x= rectsize-1; x>=0; x--)
rect[x]= PASS_VECTOR_MAX;
}
- else
- rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
+ else if(passtype==SCE_PASS_Z) {
+ rect= rpass->rect;
+ for(x= rectsize-1; x>=0; x--)
+ rect[x]= 10e10;
+ }
}
}
@@ -496,6 +522,7 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
strcpy(rl->name, srl->name);
rl->lay= srl->lay;
+ rl->lay_zmask= srl->lay_zmask;
rl->layflag= srl->layflag;
rl->passflag= srl->passflag;
rl->pass_xor= srl->pass_xor;
@@ -525,22 +552,20 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
if(srl->passflag & SCE_PASS_SPEC)
render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
- if(re->r.mode & R_SHADOW)
- if(srl->passflag & SCE_PASS_SHADOW)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
- if(re->r.mode & R_RAYTRACE) {
- if(srl->passflag & SCE_PASS_AO)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
- if(srl->passflag & SCE_PASS_REFLECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
- if(srl->passflag & SCE_PASS_REFRACT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
- }
- if(re->r.mode & R_RADIO)
- if(srl->passflag & SCE_PASS_RADIO)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_RADIO);
+ if(srl->passflag & SCE_PASS_AO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
+ if(srl->passflag & SCE_PASS_SHADOW)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
+ if(srl->passflag & SCE_PASS_REFLECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
+ if(srl->passflag & SCE_PASS_REFRACT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
+ if(srl->passflag & SCE_PASS_RADIO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_RADIO);
if(srl->passflag & SCE_PASS_INDEXOB)
render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
+ if(srl->passflag & SCE_PASS_MIST)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST);
}
/* sss, previewrender and envmap don't do layers, so we make a default one */
@@ -575,14 +600,13 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
static int render_scene_needs_vector(Render *re)
{
- if((re->r.scemode & R_DOCOMP) || re->r.imtype==R_MULTILAYER) {
- SceneRenderLayer *srl;
+ SceneRenderLayer *srl;
- for(srl= re->scene->r.layers.first; srl; srl= srl->next)
- if(!(srl->layflag & SCE_LAY_DISABLE))
- if(srl->passflag & SCE_PASS_VECTOR)
- return 1;
- }
+ for(srl= re->scene->r.layers.first; srl; srl= srl->next)
+ if(!(srl->layflag & SCE_LAY_DISABLE))
+ if(srl->passflag & SCE_PASS_VECTOR)
+ return 1;
+
return 0;
}
@@ -640,9 +664,8 @@ static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
}
-static void save_render_result_tile(Render *re, RenderPart *pa)
+static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
{
- RenderResult *rrpart= pa->result;
RenderLayer *rlp;
RenderPass *rpassp;
int offs, partx, party;
@@ -662,23 +685,23 @@ static void save_render_result_tile(Render *re, RenderPart *pa)
if(rlp->rectf) {
int a, xstride= 4;
for(a=0; a<xstride; a++)
- IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride*pa->rectx, rlp->rectf+a + xstride*offs);
+ IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
+ xstride, xstride*rrpart->rectx, rlp->rectf+a + xstride*offs);
}
/* passes are allocated in sync */
for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) {
int a, xstride= rpassp->channels;
for(a=0; a<xstride; a++)
- IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
- xstride, xstride*pa->rectx, rpassp->rect+a + xstride*offs);
+ IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
+ xstride, xstride*rrpart->rectx, rpassp->rect+a + xstride*offs);
}
}
party= rrpart->tilerect.ymin + rrpart->crop;
partx= rrpart->tilerect.xmin + rrpart->crop;
- IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
+ IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0);
BLI_unlock_thread(LOCK_IMAGE);
@@ -687,14 +710,17 @@ static void save_render_result_tile(Render *re, RenderPart *pa)
static void save_empty_result_tiles(Render *re)
{
RenderPart *pa;
+ RenderResult *rr;
- IMB_exrtile_clear_channels(re->result->exrhandle);
+ for(rr= re->result; rr; rr= rr->next) {
+ IMB_exrtile_clear_channels(rr->exrhandle);
- for(pa= re->parts.first; pa; pa= pa->next) {
- if(pa->ready==0) {
- int party= pa->disprect.ymin - re->disprect.ymin + pa->crop;
- int partx= pa->disprect.xmin - re->disprect.xmin + pa->crop;
- IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready==0) {
+ int party= pa->disprect.ymin - re->disprect.ymin + pa->crop;
+ int partx= pa->disprect.xmin - re->disprect.xmin + pa->crop;
+ IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0);
+ }
}
}
}
@@ -722,6 +748,8 @@ void RE_WriteRenderResult(RenderResult *rr, char *filename, int compress)
RenderLayer *rl;
RenderPass *rpass;
void *exrhandle= IMB_exr_get_handle();
+
+ BLI_make_existing_file(filename);
/* composite result */
if(rr->rectf) {
@@ -821,7 +849,7 @@ static void renderresult_add_names(RenderResult *rr)
/* only for temp buffer files, makes exact copy of render result */
-static void read_render_result(Render *re)
+static void read_render_result(Render *re, int sample)
{
RenderLayer *rl;
RenderPass *rpass;
@@ -832,14 +860,16 @@ static void read_render_result(Render *re)
RE_FreeRenderResult(re->result);
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
- render_unique_exr_name(re, str);
+ render_unique_exr_name(re, str, sample);
if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
IMB_exr_close(exrhandle);
printf("cannot read: %s\n", str);
return;
}
- if(rectx!=re->result->rectx || recty!=re->result->recty) {
+ printf("read exr tmp file: %s\n", str);
+
+ if(re->result == NULL || rectx!=re->result->rectx || recty!=re->result->recty) {
printf("error in reading render result\n");
}
else {
@@ -930,7 +960,6 @@ void RE_GetResultImage(Render *re, RenderResult *rr)
}
}
-#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
/* caller is responsible for allocating rect in correct size! */
void RE_ResultGet32(Render *re, unsigned int *rect)
{
@@ -962,6 +991,7 @@ RenderStats *RE_GetStats(Render *re)
return &re->i;
}
+/* Note, when rendering from a scene, ALWAYS use G.scene->id.name, else compositing wont work */
Render *RE_NewRender(const char *name)
{
Render *re;
@@ -1022,7 +1052,7 @@ void RE_FreeAllRender(void)
/* what doesn't change during entire render sequence */
/* disprect is optional, if NULL it assumes full window render */
-void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect)
+void RE_InitState(Render *re, Render *source, RenderData *rd, int winx, int winy, rcti *disprect)
{
re->ok= TRUE; /* maybe flag */
@@ -1045,18 +1075,36 @@ void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect
}
if(re->rectx < 2 || re->recty < 2 || (BKE_imtype_is_movie(rd->imtype) &&
-(re->rectx < 16 || re->recty < 16) )) {
+ (re->rectx < 16 || re->recty < 16) )) {
re->error("Image too small");
re->ok= 0;
}
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;
+#ifndef WITH_OPENEXR
+ /* can't do this without openexr support */
+ re->r.scemode &= ~R_EXR_TILE_FILE;
+#endif
+
+ if(!(re->r.scemode & R_EXR_TILE_FILE))
+ re->r.scemode &= ~R_FULL_SAMPLE; /* clear, so we can use this flag for test both */
+ /* 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;
+ }
+
/* always call, checks for gamma, gamma tables and jitter too */
make_sample_tables(re);
@@ -1069,11 +1117,11 @@ void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect
/* 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);
- if(commandline_threads>0 && commandline_threads<=BLENDER_MAX_THREADS)
- re->r.threads= commandline_threads;
+ RE_init_threadcount(re);
}
}
+/* part of external api, not called for regular render pipeline */
void RE_SetDispRect (struct Render *re, rcti *disprect)
{
re->disprect= *disprect;
@@ -1174,13 +1222,36 @@ static int render_display_draw_enabled(Render *re)
return 1;
}
+/* allocate osa new results for samples */
+static RenderResult *new_full_sample_buffers(Render *re, ListBase *lb, rcti *partrct, int crop)
+{
+ int a;
+
+ if(re->osa==0)
+ return new_render_result(re, partrct, crop, RR_USEMEM);
+
+ for(a=0; a<re->osa; a++) {
+ RenderResult *rr= new_render_result(re, partrct, crop, RR_USEMEM);
+ BLI_addtail(lb, rr);
+ rr->sample_nr= a;
+ }
+
+ return lb->first;
+}
+
+
+/* the main thread call, renders an entire part */
static void *do_part_thread(void *pa_v)
{
RenderPart *pa= pa_v;
/* need to return nicely all parts on esc */
if(R.test_break()==0) {
- pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM);
+
+ if(!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
+ pa->result= new_full_sample_buffers(&R, &pa->fullresult, &pa->disprect, pa->crop);
+ else
+ pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM);
if(R.sss_points)
zbufshade_sss_tile(pa);
@@ -1190,8 +1261,13 @@ static void *do_part_thread(void *pa_v)
zbufshade_tile(pa);
/* merge too on break! */
- if(R.result->exrhandle)
- save_render_result_tile(&R, pa);
+ if(R.result->exrhandle) {
+ RenderResult *rr, *rrpart;
+
+ for(rr= R.result, rrpart= pa->result; rr && rrpart; rr= rr->next, rrpart= rrpart->next)
+ save_render_result_tile(rr, rrpart);
+
+ }
else if(render_display_draw_enabled(&R))
merge_render_result(R.result, pa->result);
}
@@ -1365,33 +1441,54 @@ static void print_part_stats(Render *re, RenderPart *pa)
re->i.infostr= NULL;
}
+/* make osa new results for samples */
+static RenderResult *new_full_sample_buffers_exr(Render *re)
+{
+ int a;
+
+ for(a=0; a<re->osa; a++) {
+ RenderResult *rr= new_render_result(re, &re->disprect, 0, 1);
+ BLI_addtail(&re->fullresult, rr);
+ rr->sample_nr= a;
+ }
+
+ return re->fullresult.first;
+}
+
static void threaded_tile_processor(Render *re)
{
ListBase threads;
RenderPart *pa, *nextpa;
- RenderResult *rr;
rctf viewplane= re->viewplane;
int rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
- /* first step; the entire render result, or prepare exr buffer saving */
+ /* first step; free the entire render result, make new, and/or prepare exr buffer saving */
RE_FreeRenderResult(re->result);
- rr= re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
- if(rr==NULL)
+ if(re->sss_points)
+ re->result= new_render_result(re, &re->disprect, 0, 0);
+ else if(re->r.scemode & R_FULL_SAMPLE)
+ re->result= new_full_sample_buffers_exr(re);
+ else
+ re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
+
+ if(re->result==NULL)
return;
+
/* warning; no return here without closing exr file */
-// if(re->re->test_break())
-// return;
initparts(re);
- if(rr->exrhandle) {
+ if(re->result->exrhandle) {
+ RenderResult *rr;
char str[FILE_MAX];
- render_unique_exr_name(re, str);
+ for(rr= re->result; rr; rr= rr->next) {
+ render_unique_exr_name(re, str, rr->sample_nr);
- printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
- IMB_exrtile_begin_write(rr->exrhandle, str, rr->rectx, rr->recty, rr->rectx/re->xparts, rr->recty/re->yparts);
+ printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
+ IMB_exrtile_begin_write(rr->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party);
+ }
}
BLI_init_threads(&threads, do_part_thread, re->r.threads);
@@ -1446,7 +1543,7 @@ static void threaded_tile_processor(Render *re)
re->display_draw(pa->result, NULL);
print_part_stats(re, pa);
- RE_FreeRenderResult(pa->result);
+ free_render_result(&pa->fullresult, pa->result);
pa->result= NULL;
re->i.partsdone++;
hasdrawn= 1;
@@ -1470,11 +1567,20 @@ static void threaded_tile_processor(Render *re)
}
- if(rr->exrhandle) {
+ if(re->result->exrhandle) {
+ RenderResult *rr;
+
save_empty_result_tiles(re);
- IMB_exr_close(rr->exrhandle);
- rr->exrhandle= NULL;
- read_render_result(re);
+
+ for(rr= re->result; rr; rr= rr->next) {
+ IMB_exr_close(rr->exrhandle);
+ rr->exrhandle= NULL;
+ }
+
+ free_render_result(&re->fullresult, re->result);
+ re->result= NULL;
+
+ read_render_result(re, 0);
}
/* unset threadsafety */
@@ -1492,14 +1598,16 @@ void RE_TileProcessor(Render *re, int firsttile, int threaded)
re->i.partsdone= firsttile;
- re->i.starttime= PIL_check_seconds_timer();
+ if(!re->sss_points)
+ re->i.starttime= PIL_check_seconds_timer();
if(threaded)
threaded_tile_processor(re);
else
render_tile_processor(re, firsttile);
- re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
+ if(!re->sss_points)
+ re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
re->stats_draw(&re->i);
}
@@ -1722,7 +1830,8 @@ static void load_backbuffer(Render *re)
char name[256];
strcpy(name, re->r.backbuf);
- BLI_convertstringcode(name, G.sce, re->r.cfra);
+ BLI_convertstringcode(name, G.sce);
+ BLI_convertstringframe(name, re->r.cfra);
if(re->backbuf) {
re->backbuf->id.us--;
@@ -1778,6 +1887,7 @@ static void do_render_fields_blur_3d(Render *re)
re->result->tilerect= re->disprect;
/* this copying sequence could become function? */
+ /* weak is: it chances disprect from border */
re->disprect.xmin= re->disprect.ymin= 0;
re->disprect.xmax= re->winx;
re->disprect.ymax= re->winy;
@@ -1807,14 +1917,18 @@ static void do_render_fields_blur_3d(Render *re)
static void render_scene(Render *re, Scene *sce, int cfra)
{
Render *resc= RE_NewRender(sce->id.name);
+ int winx= re->winx, winy= re->winy;
sce->r.cfra= cfra;
- /* initial setup */
- RE_InitState(resc, &sce->r, re->winx, re->winy, &re->disprect);
+ /* exception: scene uses own size (unfinished code) */
+ if(0) {
+ winx= (sce->r.size*sce->r.xsch)/100;
+ winy= (sce->r.size*sce->r.ysch)/100;
+ }
- /* this to enable this scene to create speed vectors */
- resc->r.scemode |= R_DOCOMP;
+ /* initial setup */
+ RE_InitState(resc, re, &sce->r, winx, winy, &re->disprect);
/* still unsure entity this... */
resc->scene= sce;
@@ -1830,10 +1944,15 @@ static void render_scene(Render *re, Scene *sce, int cfra)
do_render_fields_blur_3d(resc);
}
-static void ntree_render_scenes(Render *re)
+static void tag_scenes_for_render(Render *re)
{
bNode *node;
- int cfra= re->scene->r.cfra;
+ Scene *sce;
+
+ for(sce= G.main->scene.first; sce; sce= sce->id.next)
+ sce->id.flag &= ~LIB_DOIT;
+
+ re->scene->id.flag |= LIB_DOIT;
if(re->scene->nodetree==NULL) return;
@@ -1843,12 +1962,21 @@ static void ntree_render_scenes(Render *re)
if(node->id) {
if(node->id != (ID *)re->scene)
node->id->flag |= LIB_DOIT;
- else
- node->id->flag &= ~LIB_DOIT;
}
}
}
+}
+
+static void ntree_render_scenes(Render *re)
+{
+ bNode *node;
+ int cfra= re->scene->r.cfra;
+
+ if(re->scene->nodetree==NULL) return;
+
+ tag_scenes_for_render(re);
+
/* now foreach render-result node tagged we do a full render */
/* results are stored in a way compisitor will find it */
for(node= re->scene->nodetree->nodes.first; node; node= node->next) {
@@ -1894,6 +2022,115 @@ static void render_composit_stats(char *str)
R.i.infostr= NULL;
}
+
+/* reads all buffers, calls optional composite, merges in first result->rectf */
+static void do_merge_fullsample(Render *re, bNodeTree *ntree)
+{
+ float *rectf, filt[3][3];
+ int sample;
+
+ /* filtmask needs it */
+ R= *re;
+
+ /* we accumulate in here */
+ rectf= MEM_mapallocN(re->rectx*re->recty*sizeof(float)*4, "fullsample rgba");
+
+ for(sample=0; sample<re->r.osa; sample++) {
+ RenderResult rres;
+ int x, y, mask;
+
+ /* set all involved renders on the samplebuffers (first was done by render itself) */
+ /* also function below assumes this */
+ if(sample) {
+ Render *re1;
+
+ tag_scenes_for_render(re);
+ for(re1= RenderList.first; re1; re1= re1->next) {
+ if(re1->scene->id.flag & LIB_DOIT)
+ if(re1->r.scemode & R_FULL_SAMPLE)
+ read_render_result(re1, sample);
+ }
+ }
+
+ /* composite */
+ if(ntree) {
+ ntreeCompositTagRender(re->scene);
+ ntreeCompositTagAnimated(ntree);
+
+ ntreeCompositExecTree(ntree, &re->r, G.background==0);
+ }
+
+ /* ensure we get either composited result or the active layer */
+ RE_GetResultImage(re, &rres);
+
+ /* accumulate with filter, and clip */
+ mask= (1<<sample);
+ mask_array(mask, filt);
+
+ for(y=0; y<re->recty; y++) {
+ float *rf= rectf + 4*y*re->rectx;
+ float *col= rres.rectf + 4*y*re->rectx;
+
+ for(x=0; x<re->rectx; x++, rf+=4, col+=4) {
+ if(col[0]<0.0f) col[0]=0.0f; else if(col[0] > 1.0f) col[0]= 1.0f;
+ if(col[1]<0.0f) col[1]=0.0f; else if(col[1] > 1.0f) col[1]= 1.0f;
+ if(col[2]<0.0f) col[2]=0.0f; else if(col[2] > 1.0f) col[2]= 1.0f;
+
+ add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ }
+ }
+
+ /* 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->display_draw(re->result, NULL);
+ }
+
+ if(re->test_break())
+ break;
+ }
+
+ if(re->result->rectf)
+ MEM_freeN(re->result->rectf);
+ re->result->rectf= rectf;
+}
+
+void RE_MergeFullSample(Render *re, Scene *sce, bNodeTree *ntree)
+{
+ Scene *scene;
+ bNode *node;
+
+ /* first call RE_ReadRenderResult on every renderlayer scene. this creates Render structs */
+
+ /* tag scenes unread */
+ for(scene= G.main->scene.first; scene; scene= scene->id.next)
+ scene->id.flag |= LIB_DOIT;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS) {
+ Scene *nodescene= (Scene *)node->id;
+
+ if(nodescene==NULL) nodescene= sce;
+ if(nodescene->id.flag & LIB_DOIT) {
+ nodescene->r.mode |= R_OSA; /* render struct needs tables */
+ RE_ReadRenderResult(sce, nodescene);
+ nodescene->id.flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ /* own render result should be read/allocated */
+ if(G.scene->id.flag & LIB_DOIT)
+ RE_ReadRenderResult(G.scene, G.scene);
+
+ /* and now we can draw (result is there) */
+ re->display_init(re->result);
+ re->display_clear(re->result);
+
+ do_merge_fullsample(re, ntree);
+}
+
/* returns fully composited render-result on given time step (in RenderData) */
static void do_render_composite_fields_blur_3d(Render *re)
{
@@ -1913,25 +2150,36 @@ static void do_render_composite_fields_blur_3d(Render *re)
if(re->r.scemode & R_SINGLE_LAYER)
pop_render_result(re);
- if(!re->test_break() && ntree) {
- ntreeCompositTagRender(re->scene);
- ntreeCompositTagAnimated(ntree);
+ if(!re->test_break()) {
- if(re->r.scemode & R_DOCOMP) {
- /* checks if there are render-result nodes that need scene */
- if((re->r.scemode & R_SINGLE_LAYER)==0)
- ntree_render_scenes(re);
-
- if(!re->test_break()) {
- ntree->stats_draw= render_composit_stats;
- ntree->test_break= re->test_break;
- /* in case it was never initialized */
- R.stats_draw= re->stats_draw;
+ if(ntree) {
+ ntreeCompositTagRender(re->scene);
+ ntreeCompositTagAnimated(ntree);
+ }
+
+ if(1 || !(re->r.scemode & R_COMP_RERENDER)) {
+ if(ntree && re->r.scemode & R_DOCOMP) {
+ /* checks if there are render-result nodes that need scene */
+ if((re->r.scemode & R_SINGLE_LAYER)==0)
+ ntree_render_scenes(re);
- ntreeCompositExecTree(ntree, &re->r, G.background==0);
- ntree->stats_draw= NULL;
- ntree->test_break= NULL;
+ if(!re->test_break()) {
+ ntree->stats_draw= render_composit_stats;
+ ntree->test_break= re->test_break;
+ /* in case it was never initialized */
+ R.stats_draw= re->stats_draw;
+
+ if(re->r.scemode & R_FULL_SAMPLE)
+ do_merge_fullsample(re, ntree);
+ else
+ ntreeCompositExecTree(ntree, &re->r, G.background==0);
+
+ ntree->stats_draw= NULL;
+ ntree->test_break= NULL;
+ }
}
+ else if(re->r.scemode & R_FULL_SAMPLE)
+ do_merge_fullsample(re, NULL);
}
}
@@ -2008,7 +2256,7 @@ static void renderresult_stampinfo()
RenderResult rres;
/* this is the basic trick to get the displayed float or char rect from render result */
RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
- BKE_stamp_buf((unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty);
+ BKE_stamp_buf((unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -2086,14 +2334,26 @@ static int is_rendering_allowed(Render *re)
if(re->r.scemode & R_EXR_TILE_FILE) {
char str[FILE_MAX];
- render_unique_exr_name(re, str);
+ render_unique_exr_name(re, str, 0);
if (BLI_is_writable(str)==0) {
re->error("Can not save render buffers, check the temp default path");
return 0;
}
+ /* no osa + fullsample won't work... */
+ if(re->osa==0)
+ re->r.scemode &= ~R_FULL_SAMPLE;
+
+ /* no fullsample and edge */
+ if((re->r.scemode & R_FULL_SAMPLE) && (re->r.mode & R_EDGE)) {
+ re->error("Full Sample doesn't support Edge Enhance");
+ return 0;
+ }
+
}
+ else
+ re->r.scemode &= ~R_FULL_SAMPLE; /* clear to be sure */
if(re->r.scemode & R_DOCOMP) {
if(re->scene->use_nodes) {
@@ -2152,7 +2412,7 @@ static int is_rendering_allowed(Render *re)
}
/* evaluating scene options for general Blender render */
-static int render_initialize_from_scene(Render *re, Scene *scene)
+static int render_initialize_from_scene(Render *re, Scene *scene, int anim)
{
int winx, winy;
rcti disprect;
@@ -2178,31 +2438,27 @@ static int render_initialize_from_scene(Render *re, Scene *scene)
disprect.ymax= winy;
}
- if(scene->r.scemode & R_EXR_TILE_FILE) {
- int partx= winx/scene->r.xparts, party= winy/scene->r.yparts;
-
- /* stupid exr tiles dont like different sizes */
- if(winx != partx*scene->r.xparts || winy != party*scene->r.yparts) {
- re->error("Sorry... exr tile saving only allowed with equally sized parts");
- return 0;
- }
- if((scene->r.mode & R_FIELDS) && (party & 1)) {
- re->error("Sorry... exr tile saving only allowed with equally sized parts");
- return 0;
- }
+ re->scene= scene;
+
+ /* not too nice, but it survives anim-border render */
+ if(anim) {
+ re->disprect= disprect;
+ return 1;
}
+ /* check all scenes involved */
+ tag_scenes_for_render(re);
+
if(scene->r.scemode & R_SINGLE_LAYER)
push_render_result(re);
- RE_InitState(re, &scene->r, winx, winy, &disprect);
+ RE_InitState(re, NULL, &scene->r, winx, winy, &disprect);
if(!re->ok) /* if an error was printed, abort */
return 0;
/* initstate makes new result, have to send changed tags around */
ntreeCompositTagRender(re->scene);
- re->scene= scene;
if(!is_rendering_allowed(re))
return 0;
@@ -2221,7 +2477,7 @@ void RE_BlenderFrame(Render *re, Scene *scene, int frame)
scene->r.cfra= frame;
- if(render_initialize_from_scene(re, scene)) {
+ if(render_initialize_from_scene(re, scene, 0)) {
do_render_all_options(re);
}
@@ -2301,13 +2557,15 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
}
/* saves images to disk */
-void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
+void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
{
bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype);
+ unsigned int lay;
int cfrao= scene->r.cfra;
+ int nfra;
- /* do not call for each frame, it initializes & pops output window */
- if(!render_initialize_from_scene(re, scene))
+ /* do not fully call for each frame, it initializes & pops output window */
+ if(!render_initialize_from_scene(re, scene, 0))
return;
/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
@@ -2333,17 +2591,58 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
}
}
} else {
- for(scene->r.cfra= sfra;
- scene->r.cfra<=efra; scene->r.cfra++) {
+ for(nfra= sfra, scene->r.cfra= sfra; scene->r.cfra<=efra; scene->r.cfra++) {
+ char name[FILE_MAX];
+
+ /* only border now, todo: camera lens. (ton) */
+ render_initialize_from_scene(re, scene, 1);
+
+ if(nfra!=scene->r.cfra) {
+ /*
+ * Skip this frame, but update for physics and particles system.
+ * From convertblender.c:
+ * in localview, lamps are using normal layers, objects only local bits.
+ */
+ if(scene->lay & 0xFF000000)
+ lay= scene->lay & 0xFF000000;
+ else
+ lay= scene->lay;
+
+ scene_update_for_newframe(scene, lay);
+ continue;
+ }
+ else
+ nfra+= tfra;
+
+ if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH) ) {
+ BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype);
+ }
+
+ if (scene->r.mode & R_NO_OVERWRITE && BLI_exist(name)) {
+ printf("skipping existing frame \"%s\"\n", name);
+ continue;
+ }
+ if (scene->r.mode & R_TOUCH && !BLI_exist(name)) {
+ BLI_make_existing_file(name); /* makes the dir if its not there */
+ BLI_touch(name);
+ }
+
re->r.cfra= scene->r.cfra; /* weak.... */
-
+
do_render_all_options(re);
-
+
if(re->test_break() == 0) {
do_write_image_or_movie(re, scene, mh);
}
- if(G.afbreek==1) break;
+ if(G.afbreek==1) {
+ /* remove touched file */
+ if (scene->r.mode & R_TOUCH && BLI_exist(name) && BLI_filepathsize(name) == 0) {
+ BLI_delete(name, 0, 0);
+ }
+
+ break;
+ }
}
}
@@ -2359,7 +2658,7 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
/* note; repeated win/disprect calc... solve that nicer, also in compo */
-/* only temp file! */
+/* only the temp file! */
void RE_ReadRenderResult(Scene *scene, Scene *scenode)
{
Render *re;
@@ -2387,17 +2686,32 @@ void RE_ReadRenderResult(Scene *scene, Scene *scenode)
if(scenode)
scene= scenode;
- re= RE_NewRender(scene->id.name);
- RE_InitState(re, &scene->r, winx, winy, &disprect);
+ /* get render: it can be called from UI with draw callbacks */
+ re= RE_GetRender(scene->id.name);
+ if(re==NULL)
+ re= RE_NewRender(scene->id.name);
+ RE_InitState(re, NULL, &scene->r, winx, winy, &disprect);
re->scene= scene;
- read_render_result(re);
+ read_render_result(re, 0);
}
void RE_set_max_threads(int threads)
{
- if(threads>0 && threads<=BLENDER_MAX_THREADS)
+ if (threads==0) {
+ commandline_threads = BLI_system_thread_count();
+ } else if(threads>=1 && threads<=BLENDER_MAX_THREADS) {
commandline_threads= threads;
- else
+ } else {
printf("Error, threads has to be in range 1-%d\n", BLENDER_MAX_THREADS);
+ }
+}
+
+void RE_init_threadcount(Render *re)
+{
+ if(commandline_threads >= 1) { /* only set as an arg in background mode */
+ re->r.threads= MIN2(commandline_threads, BLENDER_MAX_THREADS);
+ } else if ((re->r.mode & R_FIXED_THREADS)==0 || commandline_threads == 0) { /* Automatic threads */
+ re->r.threads = BLI_system_thread_count();
+ }
}
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
index 119cceaf3c2..0e453d461ab 100644
--- a/source/blender/render/intern/source/pixelblending.c
+++ b/source/blender/render/intern/source/pixelblending.c
@@ -31,6 +31,7 @@
*/
#include <math.h>
+#include <string.h>
/* global includes */
#include "BLI_arithb.h"
@@ -91,15 +92,6 @@ void addAlphaOverFloat(float *dest, float *source)
void addAlphaUnderFloat(float *dest, float *source)
{
float mul;
-
- if( (-RE_EMPTY_COLOR_FLOAT < dest[3])
- && (dest[3] < RE_EMPTY_COLOR_FLOAT) ) {
- dest[0] = source[0];
- dest[1] = source[1];
- dest[2] = source[2];
- dest[3] = source[3];
- return;
- }
mul= 1.0 - dest[3];
@@ -212,6 +204,121 @@ void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w)
}
}
+
+void mask_array(unsigned int mask, float filt[][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:
+
+ --- --- ---
+| 2,0 | 2,1 | 2,2 |
+ --- --- ---
+| 1,0 | 1,1 | 1,2 |
+ --- --- ---
+| 0,0 | 0,1 | 0,2 |
+ --- --- ---
+*/
+
+void add_filt_fmask_coord(float filt[][3], float *col, float *rowbuf, int row_w, int col_h, int x, int y)
+{
+ 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_w;
+ fpoin[1][1]= rowbuf;
+ fpoin[2][1]= rowbuf+4*row_w;
+
+ 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;
+
+ if(y==0) {
+ 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==col_h-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==0) {
+ 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==row_w-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; }
+
+ 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)
+}
+
void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
{
/* calc the value of mask */
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index cffed99c738..60723963af9 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -24,7 +24,9 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#include <float.h>
#include <math.h>
+#include <string.h>
#include "BLI_arithb.h"
/* External modules: */
@@ -43,6 +45,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
+#include "BKE_material.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -55,6 +58,7 @@
#include "rendercore.h"
#include "shadbuf.h"
#include "pixelshading.h"
+#include "sunsky.h"
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
@@ -130,9 +134,15 @@ static void render_lighting_halo(HaloRen *har, float *colf)
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 */
+
VECCOPY(shi.co, rco);
shi.osatex= 0;
- do_lamp_tex(lar, lv, &shi, lacol);
+ do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
}
if(lar->type==LA_SPOT) {
@@ -175,7 +185,7 @@ static void render_lighting_halo(HaloRen *har, float *colf)
inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
if(inp>0.0) {
/* testshadowbuf==0.0 : 100% shadow */
- shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
+ shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
if( shadfac>0.0 ) {
shadfac*= inp*soft*lar->energy;
ir -= shadfac;
@@ -212,7 +222,7 @@ static void render_lighting_halo(HaloRen *har, float *colf)
if(i> -0.41) { /* heuristic valua! */
shadfac= 1.0;
if(lar->shb) {
- shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
+ shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
if(shadfac==0.0) continue;
i*= shadfac;
}
@@ -236,8 +246,36 @@ static void render_lighting_halo(HaloRen *har, float *colf)
}
+/**
+ * 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;
-void shadeHaloFloat(HaloRen *har, float *col, int zz,
+ 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, int zz,
float dist, float xn, float yn, short flarec)
{
/* fill in col */
@@ -256,12 +294,40 @@ void shadeHaloFloat(HaloRen *har, float *col, int zz,
}
else alpha= har->alfa;
- if(alpha==0.0) {
- col[0] = 0.0;
- col[1] = 0.0;
- col[2] = 0.0;
- col[3] = 0.0;
- return;
+ if(alpha==0.0)
+ 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, 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;
+ 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*= sqrt(sqrt(t));
+ }
}
radist= sqrt(dist);
@@ -359,21 +425,10 @@ void shadeHaloFloat(HaloRen *har, float *col, int zz,
if(ster<1.0) dist*= sqrt(ster);
}
}
-
- /* halo being intersected? */
- if(har->zs> zz-har->zd) {
- t= ((float)(zz-har->zs))/(float)har->zd;
- alpha*= sqrt(sqrt(t));
- }
/* disputable optimize... (ton) */
- if(dist<=0.00001) {
- col[0] = 0.0;
- col[1] = 0.0;
- col[2] = 0.0;
- col[3] = 0.0;
- return;
- }
+ if(dist<=0.00001)
+ return 0;
dist*= alpha;
ringf*= dist;
@@ -434,6 +489,8 @@ void shadeHaloFloat(HaloRen *har, float *col, int zz,
/* alpha requires clip, gives black dots */
if(col[3] > 1.0f)
col[3]= 1.0f;
+
+ return 1;
}
/* ------------------------------------------------------------------------- */
@@ -512,13 +569,48 @@ void shadeSkyView(float *colf, float *rco, float *view, float *dxyview)
}
}
+/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
+void shadeSunView(float *colf, float *view)
+{
+ GroupObject *go;
+ LampRen *lar;
+ float sview[3];
+ int do_init= 1;
+
+ 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) {
+
+ VECCOPY(sview, view);
+ Normalize(sview);
+ MTC_Mat3MulVecfl(R.imat, sview);
+ if (sview[2] < 0.0)
+ sview[2] = 0.0;
+ Normalize(sview);
+ do_init= 0;
+ }
+
+ 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, colf, colf+1, colf+2, lar->sunsky->skyblendfac, sun_collector);
+ }
+ }
+}
+
+
/*
Stuff the sky color into the collector.
*/
void shadeSkyPixel(float *collector, float fx, float fy)
{
float view[3], dxyview[2];
-
+
/*
The rules for sky:
1. Draw an image, if a background image was provided. Stop
@@ -530,7 +622,6 @@ void shadeSkyPixel(float *collector, float fx, float fy)
/* 1. Do a backbuffer image: */
if(R.r.bufflag & 1) {
fillBackgroundImage(collector, fx, fy);
- return;
}
else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
/* 2. solid color */
@@ -565,7 +656,20 @@ void shadeSkyPixel(float *collector, float fx, float fy)
shadeSkyView(collector, NULL, view, dxyview);
collector[3] = 0.0f;
}
+
+ calc_view_vector(view, fx, fy);
+ shadeSunView(collector, view);
}
+/* aerial perspective */
+void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance)
+{
+ float view[3];
+
+ calc_view_vector(view, fx, fy);
+ Normalize(view);
+ /*MTC_Mat3MulVecfl(R.imat, view);*/
+ AtmospherePixleShader(sunsky, view, distance, collector);
+}
/* eof */
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 69e90a7537c..f822d41bb85 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -40,8 +40,9 @@
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
-#include "BLI_rand.h"
+#include "BLI_blenlib.h"
#include "BLI_jitter.h"
+#include "BLI_rand.h"
#include "PIL_time.h"
@@ -77,15 +78,21 @@ static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, f
*v4 = (vlr->v4)? vlr->v4->co: NULL;
}
-static int vlr_check_intersect(Isect *is, RayFace *face)
+static int vlr_check_intersect(Isect *is, int ob, RayFace *face)
{
+ ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)is->userdata, ob);
VlakRen *vlr = (VlakRen*)face;
+ /* for baking selected to active non-traceable materials might still
+ * be in the raytree */
+ if(!(vlr->mat->mode & MA_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 (is->lay & vlr->lay);
+ return (is->lay & obi->lay);
}
static float *vlr_get_transform(void *userdata, int i)
@@ -110,7 +117,7 @@ void makeraytree(Render *re)
VlakRen *vlr= NULL;
float min[3], max[3], co1[3], co2[3], co3[3], co4[3];
double lasttime= PIL_check_seconds_timer();
- int v, totface = 0;
+ int v, totv = 0, totface = 0;
INIT_MINMAX(min, max);
@@ -124,7 +131,8 @@ void makeraytree(Render *re)
for(v=0;v<obr->totvlak;v++) {
if((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
else vlr++;
- if(vlr->mat->mode & MA_TRACEBLE) {
+ /* baking selected to active needs non-traceable too */
+ if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE)) {
if((vlr->mat->mode & MA_WIRE)==0) {
VECCOPY(co1, vlr->v1->co);
VECCOPY(co2, vlr->v2->co);
@@ -167,7 +175,7 @@ void makeraytree(Render *re)
if(re->excludeob && obr->ob == re->excludeob)
continue;
- for(v=0; v<obr->totvlak; v++) {
+ for(v=0; v<obr->totvlak; v++, totv++) {
if((v & 255)==0) {
double time= PIL_check_seconds_timer();
@@ -176,7 +184,7 @@ void makeraytree(Render *re)
break;
if(time-lasttime>1.0f) {
char str[32];
- sprintf(str, "Filling Octree: %d", v);
+ sprintf(str, "Filling Octree: %d", totv);
re->i.infostr= str;
re->stats_draw(&re->i);
re->i.infostr= NULL;
@@ -185,7 +193,7 @@ void makeraytree(Render *re)
}
else vlr++;
- if(vlr->mat->mode & MA_TRACEBLE)
+ if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
if((vlr->mat->mode & MA_WIRE)==0)
RE_ray_tree_add_face(re->raytree, RAY_OBJECT_SET(re, obi), vlr);
}
@@ -255,7 +263,12 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
shade_input_set_shade_texco(shi);
if(is->mode==RE_RAY_SHADOW_TRA)
- shade_color(shi, shr);
+ 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_color(shi, shr);
else {
if(shi->mat->nodetree && shi->mat->use_nodes) {
ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
@@ -376,7 +389,7 @@ static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
static void ray_fadeout_endcolor(float *col, ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, float *vec)
{
- /* un-intersected rays get either rendered material colour or sky colour */
+ /* un-intersected rays get either rendered material color or sky color */
if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) {
VECCOPY(col, shr->combined);
} else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) {
@@ -384,12 +397,13 @@ static void ray_fadeout_endcolor(float *col, ShadeInput *origshi, ShadeInput *sh
Normalize(shi->view);
shadeSkyView(col, isec->start, shi->view, NULL);
+ shadeSunView(col, shi->view);
}
}
static void ray_fadeout(Isect *is, ShadeInput *shi, float *col, float *blendcol, float dist_mir)
{
- /* if fading out, linear blend against fade colour */
+ /* if fading out, linear blend against fade color */
float blendfac;
blendfac = 1.0 - VecLenf(shi->co, is->start)/dist_mir;
@@ -409,6 +423,11 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
float ref[3], maxsize=RE_ray_tree_max_size(R.raytree);
float dist_mir = origshi->mat->dist_mir;
+ /* Warning, 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 do a memset */
+ memset(&shi, 0, sizeof(ShadeInput));
+ /* end warning! - Campbell */
+
VECCOPY(isec.start, start);
if (dist_mir > 0.0) {
isec.end[0]= start[0]+dist_mir*vec[0];
@@ -430,13 +449,13 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
shi.osatex= origshi->osatex;
shi.depth= 1; /* only used to indicate tracing */
shi.thread= origshi->thread;
- shi.sample= 0;
+ //shi.sample= 0; // memset above, so dont need this
shi.xs= origshi->xs;
shi.ys= origshi->ys;
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= 0;
+ //shi.do_preview= 0; // memset above, so dont need this
shi.light_override= origshi->light_override;
shi.mat_override= origshi->mat_override;
@@ -531,8 +550,8 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
if (dist_mir > 0.0) {
float blendcol[3];
- /* max ray distance set, but found an intersection, so fade this colour
- * out towards the sky/material colour for a smooth transition */
+ /* 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, vec);
ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
}
@@ -615,24 +634,27 @@ void init_jitter_plane(LampRen *lar)
/* 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_mallocN(x*tot*2*sizeof(float), "lamp jitter tab");
-
- /* set per-lamp fixed seed */
- BLI_srandom(tot);
-
- /* fill table with random locations, area_size large */
- for(x=0; x<tot; x++, fp+=2) {
- fp[0]= (BLI_frand()-0.5)*lar->area_size;
- fp[1]= (BLI_frand()-0.5)*lar->area_sizey;
- }
+ fp= lar->jitter= MEM_callocN(x*tot*2*sizeof(float), "lamp jitter tab");
- 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);
+ /* if 1 sample, we leave table to be zero's */
+ if(tot>1) {
+
+ /* set per-lamp fixed seed */
+ BLI_srandom(tot);
+
+ /* fill table with random locations, area_size large */
+ for(x=0; x<tot; x++, fp+=2) {
+ fp[0]= (BLI_frand()-0.5)*lar->area_size;
+ fp[1]= (BLI_frand()-0.5)*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);
+ }
+ }
+ }
/* 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);
@@ -715,10 +737,10 @@ static void hammersley_create(double *out, int n)
}
}
-struct QMCSampler *QMC_initSampler(int type, int tot)
+static struct QMCSampler *QMC_initSampler(int type, int tot)
{
- QMCSampler *qsa = MEM_mallocN(sizeof(QMCSampler), "qmc sampler");
- qsa->samp2d = MEM_mallocN(2*sizeof(double)*tot, "qmc sample table");
+ 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;
@@ -859,25 +881,55 @@ static void QMC_sampleHemiCosine(float *vec, QMCSampler *qsa, int thread, int nu
#endif
/* called from convertBlenderScene.c */
-/* samples don't change per pixel, so build the samples in advance for efficiency */
-void init_lamp_hammersley(LampRen *lar)
+void init_render_qmcsampler(Render *re)
{
- lar->qsa = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, lar->ray_totsamp);
+ re->qmcsamplers= MEM_callocN(sizeof(ListBase)*BLENDER_MAX_THREADS, "QMCListBase");
}
-void init_render_hammersley(Render *re)
+static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
{
- re->qsa = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, (re->wrld.aosamp * re->wrld.aosamp));
+ 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= 1;
+ return qsa;
+ }
+ }
+
+ qsa= QMC_initSampler(type, tot);
+ qsa->used= 1;
+ BLI_addtail(&re->qmcsamplers[thread], qsa);
+
+ return qsa;
}
-void free_lamp_qmcsampler(LampRen *lar)
+static void release_thread_qmcsampler(Render *re, int thread, QMCSampler *qsa)
{
- QMC_freeSampler(lar->qsa);
+ qsa->used= 0;
}
void free_render_qmcsampler(Render *re)
{
- QMC_freeSampler(re->qsa);
+ QMCSampler *qsa, *next;
+ int a;
+
+ if(re->qmcsamplers) {
+ for(a=0; a<BLENDER_MAX_THREADS; 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, float *col, float *colsq, float thresh)
@@ -954,7 +1006,7 @@ static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
else samp_type = SAMP_TYPE_HAMMERSLEY;
/* all samples are generated per pixel */
- qsa = QMC_initSampler(samp_type, max_samples);
+ qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
QMC_initPixel(qsa, shi->thread);
} else
max_samples = 1;
@@ -1012,7 +1064,8 @@ static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
col[2] /= (float)samples;
col[3] /= (float)samples;
- if (qsa) QMC_freeSampler(qsa);
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
}
static void trace_reflect(float *col, ShadeInput *shi, ShadeResult *shr, float fresnelfac)
@@ -1039,7 +1092,7 @@ static void trace_reflect(float *col, ShadeInput *shi, ShadeResult *shr, float f
else samp_type = SAMP_TYPE_HAMMERSLEY;
/* all samples are generated per pixel */
- qsa = QMC_initSampler(samp_type, max_samples);
+ qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
QMC_initPixel(qsa, shi->thread);
} else
max_samples = 1;
@@ -1117,13 +1170,13 @@ static void trace_reflect(float *col, ShadeInput *shi, ShadeResult *shr, float f
col[1] /= (float)samples;
col[2] /= (float)samples;
- if (qsa) QMC_freeSampler(qsa);
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
}
/* extern call from render loop */
void ray_trace(ShadeInput *shi, ShadeResult *shr)
{
- VlakRen *vlr;
float i, f, f1, fr, fg, fb;
float mircol[4], tracol[4];
float diff[3];
@@ -1131,7 +1184,7 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr)
do_tra= ((shi->mat->mode & (MA_RAYTRANSP)) && shr->alpha!=1.0f);
do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0f);
- vlr= shi->vlr;
+
/* raytrace mirror amd refract like to separate the spec color */
if(shi->combinedflag & SCE_PASS_SPEC)
@@ -1231,16 +1284,22 @@ static void ray_trace_shadow_tra(Isect *is, int depth, int traflag)
float d= 1.0f;
/* we got a face */
+ /* Warning, 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 do a memset */
+ memset(&shi, 0, sizeof(ShadeInput));
+ /* end warning! - Campbell */
+
shi.depth= 1; /* only used to indicate tracing */
shi.mask= 1;
- shi.osatex= 0;
+
+ /*shi.osatex= 0;
shi.thread= shi.sample= 0;
shi.lay= 0;
shi.passflag= 0;
shi.combinedflag= 0;
shi.do_preview= 0;
shi.light_override= NULL;
- shi.mat_override= NULL;
+ shi.mat_override= NULL;*/
shade_ray(is, &shi, &shr);
if (traflag & RAY_TRA)
@@ -1300,6 +1359,12 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
if(RE_ray_tree_intersect(R.raytree, &isec)) {
float fac;
+
+ /* Warning, 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 do a memset */
+ memset(&shi, 0, sizeof(ShadeInput));
+ /* end warning! - Campbell */
+
shade_ray(&isec, &shi, &shr_t);
fac= isec.labda*isec.labda;
fac= 1.0f;
@@ -1416,14 +1481,15 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys)
int tot;
float *vec;
- if(resol>16) resol= 16;
-
tot= 2*resol*resol;
if (type & WO_AORNDSMP) {
- static float sphere[2*3*256];
+ float *sphere;
int a;
+ // always returns table
+ sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
+
/* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
vec= sphere;
for (a=0; a<tot; a++, vec+=3) {
@@ -1438,7 +1504,8 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys)
float ang, *vec1;
int a;
- sphere= threadsafe_table_sphere(1, thread, xs, ys, tot); // returns table if xs and ys were equal to last call
+ // returns table if xs and ys were equal to last call
+ sphere= threadsafe_table_sphere(1, thread, xs, ys, tot);
if(sphere==NULL) {
sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
@@ -1460,7 +1527,7 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys)
}
}
-void ray_ao_qmc(ShadeInput *shi, float *shadfac)
+static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
{
Isect isec;
QMCSampler *qsa=NULL;
@@ -1471,7 +1538,6 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
float fac=0.0f, prev=0.0f;
float adapt_thresh = G.scene->world->ao_adapt_thresh;
float adapt_speed_fac = G.scene->world->ao_adapt_speed_fac;
- float bias = G.scene->world->aobias;
int samples=0;
int max_samples = R.wrld.aosamp*R.wrld.aosamp;
@@ -1485,7 +1551,6 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
isec.ob_last= 0;
isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
isec.lay= -1;
- VECCOPY(isec.start, shi->co);
shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
@@ -1500,13 +1565,10 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
dxyview[2]= 0.0f;
}
- /* bias prevents smoothed faces to appear flat */
if(shi->vlr->flag & R_SMOOTH) {
- bias= G.scene->world->aobias;
VECCOPY(nrm, shi->vn);
}
else {
- bias= 0.0f;
VECCOPY(nrm, shi->facenor);
}
@@ -1521,9 +1583,9 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
max_samples /= speedfac;
if (max_samples < 5) max_samples = 5;
- qsa = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
} else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
- qsa = R.qsa;
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
QMC_initPixel(qsa, shi->thread);
@@ -1538,6 +1600,7 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
Normalize(dir);
+ VECCOPY(isec.start, shi->co);
isec.end[0] = shi->co[0] - maxdist*dir[0];
isec.end[1] = shi->co[1] - maxdist*dir[1];
isec.end[2] = shi->co[2] - maxdist*dir[2];
@@ -1565,6 +1628,7 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
}
else { /* WO_AOSKYTEX */
shadeSkyView(skycol, isec.start, view, dxyview);
+ shadeSunView(skycol, shi->view);
shadfac[0]+= skycol[0];
shadfac[1]+= skycol[1];
shadfac[2]+= skycol[2];
@@ -1595,17 +1659,18 @@ void ray_ao_qmc(ShadeInput *shi, float *shadfac)
shadfac[0]= shadfac[1]= shadfac[2]= 1.0f - fac/(float)samples;
}
- if ((qsa) && (qsa->type == SAMP_TYPE_HALTON)) QMC_freeSampler(qsa);
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
}
/* extern call from shade_lamp_loop, ambient occlusion calculus */
-void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
+static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
{
Isect isec;
float *vec, *nrm, div, bias, sh=0.0f;
float maxdist = R.wrld.aodist;
float dxyview[3];
- int j= -1, tot, actual=0, skyadded=0, aocolor;
+ int j= -1, tot, actual=0, skyadded=0, aocolor, resol= R.wrld.aosamp;
isec.faceorig= (RayFace*)shi->vlr;
isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
@@ -1632,14 +1697,16 @@ void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
if(shi->mat->mode & MA_ONLYSHADOW)
aocolor= WO_AOPLAIN;
- vec= sphere_sampler(R.wrld.aomode, R.wrld.aosamp, shi->thread, shi->xs, shi->ys);
+ if(resol>32) resol= 32;
+
+ vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys);
// warning: since we use full sphere now, and dotproduct is below, we do twice as much
- tot= 2*R.wrld.aosamp*R.wrld.aosamp;
+ tot= 2*resol*resol;
if(aocolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)R.wrld.aosamp;
- dxyview[1]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[0]= 1.0f/(float)resol;
+ dxyview[1]= 1.0f/(float)resol;
dxyview[2]= 0.0f;
}
@@ -1686,6 +1753,7 @@ void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
}
else { /* WO_AOSKYTEX */
shadeSkyView(skycol, isec.start, view, dxyview);
+ shadeSunView(skycol, shi->view);
shadfac[0]+= skycol[0];
shadfac[1]+= skycol[1];
shadfac[2]+= skycol[2];
@@ -1724,21 +1792,62 @@ void ray_ao(ShadeInput *shi, float *shadfac)
ray_ao_spheresamp(shi, shadfac);
}
+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 {
+ VECCOPY(jitco[0], shi->co);
+ *totjitco= 1;
+ }
+}
static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec)
{
QMCSampler *qsa=NULL;
- QMCSampler *qsa_jit=NULL;
int samples=0;
- float samp3d[3], jit[3];
+ float samp3d[3];
float fac=0.0f, vec[3];
float colsq[4];
float adapt_thresh = lar->adapt_thresh;
- int max_samples = lar->ray_totsamp;
- float pos[3];
+ int min_adapt_samples=4, max_samples = lar->ray_totsamp;
+ float *co;
int do_soft=1, full_osa=0;
+ 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;
@@ -1756,17 +1865,15 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
else max_samples = (R.osa > 4)?R.osa:5;
}
+ ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco);
+
/* sampling init */
- if (lar->ray_samp_method==LA_SAMP_HALTON) {
- qsa = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
- qsa_jit = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
- } else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) {
- qsa = lar->qsa;
- qsa_jit = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, max_samples);
- }
+ 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);
- QMC_initPixel(qsa_jit, shi->thread);
VECCOPY(vec, lampco);
@@ -1774,18 +1881,11 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
while (samples < max_samples) {
isec->faceorig= (RayFace*)shi->vlr;
isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
-
+
/* manually jitter the start shading co-ord per sample
* based on the pre-generated OSA texture sampling offsets,
* for anti-aliasing sharp shadow edges. */
- VECCOPY(pos, shi->co);
- if (shi->vlr && !full_osa) {
- QMC_sampleRect(jit, qsa_jit, shi->thread, samples, 1.0, 1.0);
-
- pos[0] += shi->dxco[0]*jit[0] + shi->dyco[0]*jit[1];
- pos[1] += shi->dxco[1]*jit[0] + shi->dyco[1]*jit[1];
- pos[2] += shi->dxco[2]*jit[0] + shi->dyco[2]*jit[1];
- }
+ co = jitco[samples % totjitco];
if (do_soft) {
/* sphere shadow source */
@@ -1793,9 +1893,9 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
float ru[3], rv[3], v[3], s[3];
/* calc tangent plane vectors */
- v[0] = pos[0] - lampco[0];
- v[1] = pos[1] - lampco[1];
- v[2] = pos[2] - lampco[2];
+ v[0] = co[0] - lampco[0];
+ v[1] = co[1] - lampco[1];
+ v[2] = co[2] - lampco[2];
Normalize(v);
VecOrthoBasisf(v, ru, rv);
@@ -1822,8 +1922,21 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
} else {
VECCOPY(isec->end, vec);
}
- VECCOPY(isec->start, pos);
-
+
+ if(shi->strand) {
+ /* bias away somewhat to avoid self intersection */
+ float jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco));
+ float v[3];
+
+ VECSUB(v, co, isec->end);
+ Normalize(v);
+
+ co[0] -= jitbias*v[0];
+ co[1] -= jitbias*v[1];
+ co[2] -= jitbias*v[2];
+ }
+
+ VECCOPY(isec->start, co);
/* trace the ray */
if(isec->mode==RE_RAY_SHADOW_TRA) {
@@ -1850,7 +1963,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
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 > 4) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) {
+ if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) {
if (isec->mode==RE_RAY_SHADOW_TRA) {
if ((shadfac[3] / samples > (1.0-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
break;
@@ -1872,8 +1985,8 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
} else
shadfac[3]= 1.0f-fac/samples;
- if (qsa_jit) QMC_freeSampler(qsa_jit);
- if ((qsa) && (qsa->type == SAMP_TYPE_HALTON)) QMC_freeSampler(qsa);
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
}
static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec)
@@ -1964,7 +2077,10 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
if(shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
else isec.mode= RE_RAY_SHADOW;
- if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1;
+ 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) {
@@ -2025,7 +2141,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
}
/* only when face points away from lamp, in direction of lamp, trace ray and find first exit point */
-void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co)
+static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co)
{
Isect isec;
float lampco[3], maxsize;
diff --git a/source/blender/render/intern/source/raytrace.c b/source/blender/render/intern/source/raytrace.c
index 54e8e4cfab5..ec47df74d04 100644
--- a/source/blender/render/intern/source/raytrace.c
+++ b/source/blender/render/intern/source/raytrace.c
@@ -635,6 +635,8 @@ void RE_ray_tree_done(RayTree *tree)
/* ************ raytracer **************** */
+#define ISECT_EPSILON ((float)FLT_EPSILON)
+
/* only for self-intersecting test with current render face (where ray left) */
static int intersection2(RayFace *face, int ob, RayObjectTransformFunc transformfunc, RayCoordsFunc coordsfunc, void *userdata, float r0, float r1, float r2, float rx1, float ry1, float rz1)
{
@@ -692,13 +694,13 @@ static int intersection2(RayFace *face, int ob, RayObjectTransformFunc transform
if(divdet!=0.0f) {
u1= det1/divdet;
- if(u1<=0.0f) {
+ if(u1<ISECT_EPSILON) {
det= t00*(m1*r2-m2*r1);
det+= t01*(m2*r0-m0*r2);
det+= t02*(m0*r1-m1*r0);
v= det/divdet;
- if(v<=0.0f && (u1 + v) >= -1.0f) {
+ if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) {
return 1;
}
}
@@ -714,13 +716,13 @@ static int intersection2(RayFace *face, int ob, RayObjectTransformFunc transform
if(divdet!=0.0f) {
u2= det1/divdet;
- if(u2<=0.0f) {
+ if(u2<ISECT_EPSILON) {
det= t20*(m1*r2-m2*r1);
det+= t21*(m2*r0-m0*r2);
det+= t22*(m0*r1-m1*r0);
v= det/divdet;
- if(v<=0.0f && (u2 + v) >= -1.0f) {
+ if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) {
return 2;
}
}
@@ -860,7 +862,7 @@ int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, Ra
divdet= 1.0f/divdet;
u= det1*divdet;
- if(u<0.0f && u>-1.0f) {
+ if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t02-m2*t01;
@@ -868,11 +870,11 @@ int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, Ra
cros2= m0*t01-m1*t00;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
- if(v<0.0f && (u + v) > -1.0f) {
+ if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
- if(labda>0.0f && labda<1.0f) {
+ if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
is->labda= labda;
is->u= u; is->v= v;
ok= 1;
@@ -893,18 +895,18 @@ int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, Ra
divdet= 1.0f/divdet;
u = det1*divdet;
- if(u<0.0f && u>-1.0f) {
+ if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t22-m2*t21;
cros1= m2*t20-m0*t22;
cros2= m0*t21-m1*t20;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
- if(v<0.0f && (u + v) > -1.0f) {
+ if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
- if(labda>0.0f && labda<1.0f) {
+ if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
ok= 2;
is->labda= labda;
is->u= u; is->v= v;
@@ -983,7 +985,7 @@ static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval, RayCheckFunc c
if(!(is->faceorig == face && is->oborig == ob)) {
- if(checkfunc(is, face)) {
+ if(checkfunc(is, ob, face)) {
ov= no->ov+nr;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
@@ -1023,7 +1025,7 @@ static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval, RayCheckFunc c
while(face) {
if(!(is->faceorig == face && is->oborig == ob)) {
- if(checkfunc(is, face)) {
+ if(checkfunc(is, ob, face)) {
ov= no->ov+nr;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
//accepted++;
@@ -1031,8 +1033,11 @@ static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval, RayCheckFunc c
isect.ob= ob;
isect.face= face;
if(RE_ray_face_intersection(&isect, oc->transformfunc, oc->coordsfunc)) {
- if(isect.labda<is->labda) *is= isect;
- found= 1;
+ if(isect.labda<is->labda) {
+ *is= isect;
+ found= 1;
+ }
+
}
}
//else rejected++;
@@ -1205,7 +1210,7 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
/* check with last intersected shadow face */
if(is->face_last!=NULL && !(is->face_last==is->faceorig && is->ob_last==is->oborig)) {
- if(checkfunc(is, is->face_last)) {
+ if(checkfunc(is, is->ob_last, is->face_last)) {
is->ob= is->ob_last;
is->face= is->face_last;
VECSUB(is->vec, is->end, is->start);
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 0a9078b32f0..1eb42bca569 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -29,6 +29,7 @@
/* system includes */
#include <stdio.h>
#include <math.h>
+#include <float.h>
#include <string.h>
/* External modules: */
@@ -46,6 +47,7 @@
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_group_types.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -60,6 +62,7 @@
#include "renderpipeline.h"
#include "render_types.h"
#include "renderdatabase.h"
+#include "occlusion.h"
#include "pixelblending.h"
#include "pixelshading.h"
#include "shadbuf.h"
@@ -155,7 +158,7 @@ static int calchalo_z(HaloRen *har, int zz)
{
if(har->type & HA_ONLYSKY) {
- if(zz!=0x7FFFFFFF) zz= - 0x7FFFFF;
+ if(zz < 0x7FFFFFF0) zz= - 0x7FFFFF; /* edge render messes zvalues */
}
else {
zz= (zz>>8);
@@ -163,11 +166,14 @@ static int calchalo_z(HaloRen *har, int zz)
return zz;
}
-static void halo_pixelstruct(HaloRen *har, float *rb, float dist, float xn, float yn, PixStr *ps)
+
+
+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];
- int amount, amountm, zz, flarec;
+ 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;
flarec= har->flarec;
@@ -177,50 +183,70 @@ static void halo_pixelstruct(HaloRen *har, float *rb, float dist, float xn, floa
amount+= amountm;
zz= calchalo_z(har, ps->z);
- if(zz> har->zs) {
- float fac;
-
- shadeHaloFloat(har, col, zz, dist, xn, yn, flarec);
- 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];
- flarec= 0;
+ 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))
+ addalphaAddfacFloat(rlpp[sample]->rectf + 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) {
- float fac;
+ 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];
+ }
+ }
+ }
- shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec);
- 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)))
+ addalphaAddfacFloat(rlpp[sample]->rectf + 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++)
+ addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
}
- col[0]= accol[0];
- col[1]= accol[1];
- col[2]= accol[2];
- col[3]= accol[3];
-
- addalphaAddfacFloat(rb, col, har->add);
-
}
-static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
+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, *rb;
+ float dist, xsq, ysq, xn, yn;
float col[4];
- long *rd= NULL;
- int a, *rz, zz, y;
+ intptr_t *rd= NULL;
+ int a, *rz, zz, y, sample, totsample, od;
short minx, maxx, miny, maxy, x;
+ unsigned int lay= rl->lay;
/* we don't render halos in the cropped area, gives errors in flare counter */
if(pa->crop) {
@@ -230,6 +256,8 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
testrect.ymax-= pa->crop;
}
+ totsample= get_sample_layers(pa, rl, rlpp);
+
for(a=0; a<R.tothalo; a++) {
har= R.sortedhalos[a];
@@ -254,8 +282,8 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
for(y=miny; y<maxy; y++) {
int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin);
- rb= pass + 4*rectofs;
rz= pa->rectz + rectofs;
+ od= rectofs;
if(pa->rectdaps)
rd= pa->rectdaps + rectofs;
@@ -263,19 +291,21 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
yn= (y-har->ys)*R.ycor;
ysq= yn*yn;
- for(x=minx; x<maxx; x++, rb+=4, rz++) {
+ 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, rb, dist, xn, yn, (PixStr *)*rd);
+ halo_pixelstruct(har, rlpp, totsample, od, dist, xn, yn, (PixStr *)*rd);
}
else {
zz= calchalo_z(har, *rz);
- if(zz> har->zs) {
- shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec);
- addalphaAddfacFloat(rb, col, har->add);
+ 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++)
+ addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ }
}
}
}
@@ -290,22 +320,27 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
{
+ RenderLayer *rlpp[RE_MAX_OSA];
ShadeInput shi;
- float *pass= rl->rectf;
- float fac;
- long *rd= pa->rectdaps;
- int x, y, *rz= pa->rectz;
+ float *pass;
+ float fac, col[4];
+ intptr_t *rd= pa->rectdaps;
+ int *rz= pa->rectz;
+ int x, y, sample, totsample, fullsample, od;
- shade_input_initialize(&shi, pa, rl, 0);
+ totsample= get_sample_layers(pa, rl, rlpp);
+ fullsample= (totsample > 1);
+
+ shade_input_initialize(&shi, pa, rl, 0); /* this zero's ShadeInput for us */
- for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, pass+=4) {
+ 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 samp, totsamp= 0;
+ int count, totsamp= 0, mask= 0;
while(ps) {
if(R.r.mode & R_ORTHO)
@@ -313,15 +348,64 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
else
calc_renderco_zbuf(shi.co, shi.view, ps->z);
- totsamp+= samp= count_mask(ps->mask);
- fac= ((float)samp)/(float)R.osa;
- renderspothalo(&shi, pass, fac);
+ 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= rlpp[sample]->rectf + 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= rl->rectf + 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) {
- fac= ((float)R.osa-totsamp)/(float)R.osa;
shi.co[2]= 0.0f;
- renderspothalo(&shi, pass, fac);
+
+ 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= rlpp[sample]->rectf + 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= rl->rectf + 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 {
@@ -330,7 +414,17 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
else
calc_renderco_zbuf(shi.co, shi.view, *rz);
- renderspothalo(&shi, pass, 1.0f);
+ col[0]= col[1]= col[2]= col[3]= 0.0f;
+ renderspothalo(&shi, col, 1.0f);
+
+ for(sample=0; sample<totsample; sample++) {
+ pass= rlpp[sample]->rectf + 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++;
@@ -347,12 +441,19 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr)
{
RenderPass *rpass;
+
+ /* combined rgb */
+ add_filt_fmask(curmask, shr->combined, rl->rectf + 4*offset, rectx);
for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *fp, *col= NULL;
int pixsize= 3;
switch(rpass->passtype) {
+ case SCE_PASS_Z:
+ fp= rpass->rect + offset;
+ *fp= shr->z;
+ break;
case SCE_PASS_RGBA:
col= shr->col;
pixsize= 4;
@@ -399,6 +500,12 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
*fp= (float)shi->obr->ob->index;
}
break;
+ case SCE_PASS_MIST:
+ /* */
+ col= &shr->mist;
+ pixsize= 1;
+ break;
+
case SCE_PASS_VECTOR:
{
/* add minimum speed in pixel, no filter */
@@ -425,12 +532,20 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr)
{
RenderPass *rpass;
+ float *fp;
+
+ fp= rl->rectf + 4*offset;
+ QUATCOPY(fp, shr->combined);
for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *fp, *col= NULL, uvcol[3];
+ float *col= NULL, uvcol[3];
int a, pixsize= 3;
switch(rpass->passtype) {
+ case SCE_PASS_Z:
+ fp= rpass->rect + offset;
+ *fp= shr->z;
+ break;
case SCE_PASS_RGBA:
col= shr->col;
pixsize= 4;
@@ -477,6 +592,10 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
*fp= (float)shi->obr->ob->index;
}
break;
+ case SCE_PASS_MIST:
+ fp= rpass->rect + offset;
+ *fp= shr->mist;
+ break;
}
if(col) {
fp= rpass->rect + pixsize*offset;
@@ -486,26 +605,60 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
}
}
+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, float *pass)
+static void sky_tile(RenderPart *pa, RenderLayer *rl)
{
- float col[4];
- int x, y;
+ 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++, pass+=4) {
- if(pass[3]<1.0f) {
- if(pass[3]==0.0f)
- shadeSkyPixel(pass, x, y);
- else {
- shadeSkyPixel(col, x, y);
- addAlphaOverFloat(col, pass);
- QUATCOPY(pass, col);
+ for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od+=4) {
+ float col[4];
+ int sample, done= 0;
+
+ for(sample= 0; sample<totsample; sample++) {
+ float *pass= rlpp[sample]->rectf + od;
+
+ if(pass[3]<1.0f) {
+
+ if(done==0) {
+ shadeSkyPixel(col, x, y);
+ done= 1;
+ }
+
+ if(pass[3]==0.0f) {
+ QUATCOPY(pass, col);
+ }
+ else {
+ addAlphaUnderFloat(pass, col);
+ }
}
- }
+ }
}
if(y&1)
@@ -513,14 +666,99 @@ static void sky_tile(RenderPart *pa, float *pass)
}
}
+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(zpass->passtype==SCE_PASS_Z)
+ break;
+
+ if(zpass==NULL) return;
+
+ /* check for at least one sun lamp that its atmosphere flag is 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++) {
+ float *zrect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z) + od;
+ float *rgbrect = rlpp[sample]->rectf + 4*od;
+ float rgb[3];
+ int done= 0;
+
+ 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.9e10 || rgbrect[3]==0.0f) {
+ continue;
+ }
+
+ if((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) {
+ float tmp_rgb[3];
+
+ VECCOPY(tmp_rgb, rgbrect);
+ if(rgbrect[3]!=1.0f) { /* de-premul */
+ float div= 1.0f/rgbrect[3];
+ VECMUL(tmp_rgb, div);
+ }
+ shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect);
+ if(rgbrect[3]!=1.0f) { /* premul */
+ VECMUL(tmp_rgb, rgbrect[3]);
+ }
+
+ if(done==0) {
+ VECCOPY(rgb, tmp_rgb);
+ done = 1;
+ }
+ 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) {
+ VECCOPY(rgbrect, rgb);
+ }
+ }
+ }
+ }
+}
+
static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
{
RenderResult *rr= pa->result;
ShadeSample ssamp;
- float *fcol, *rf, *rectf= rl->rectf;
- long *rd, *rectdaps= pa->rectdaps;
+ intptr_t *rd, *rectdaps= pa->rectdaps;
int samp;
- int x, y, seed, crop=0, offs=0, od, addpassflag;
+ int x, y, seed, crop=0, offs=0, od;
if(R.test_break()) return;
@@ -533,12 +771,14 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
/* general shader info, passes */
shade_sample_initialize(&ssamp, pa, rl);
- addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
-
+
+ /* 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;
- rectf+= 4*(pa->rectx + 1);
rectdaps+= pa->rectx + 1;
offs= pa->rectx + 1;
}
@@ -549,28 +789,35 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
rr->renlay= rl;
for(y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- rf= rectf;
rd= rectdaps;
od= offs;
- for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, rf+=4, od++) {
+ 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)) {
- for(samp=0; samp<ssamp.tot; samp++) {
-
- fcol= ssamp.shr[samp].combined;
- add_filt_fmask(ssamp.shi[samp].mask, fcol, rf, pa->rectx);
-
- if(addpassflag)
+
+ /* 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]);
}
}
}
}
- rectf+= 4*pa->rectx;
rectdaps+= pa->rectx;
offs+= pa->rectx;
@@ -582,6 +829,9 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
if(R.r.mode & R_SHADOW)
ISB_free(pa);
+
+ if(R.occlusiontree)
+ free_occ_samples(&R, pa);
}
/* ************* pixel struct ******** */
@@ -613,7 +863,7 @@ static void freeps(ListBase *lb)
lb->first= lb->last= NULL;
}
-static void addps(ListBase *lb, long *rd, int obi, int facenr, int z, unsigned short mask)
+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;
@@ -640,12 +890,13 @@ static void addps(ListBase *lb, long *rd, int obi, int facenr, int z, unsigned s
ps= psm->ps + psm->counter++;
if(last) last->next= ps;
- else *rd= (long)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;
}
@@ -669,23 +920,29 @@ static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
}
}
-
-static void convert_to_key_alpha(RenderPart *pa, float *rectf)
+static void convert_to_key_alpha(RenderPart *pa, RenderLayer *rl)
{
- int y;
-
- for(y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
- if(rectf[3] >= 1.0f);
- else if(rectf[3] > 0.0f) {
- rectf[0] /= rectf[3];
- rectf[1] /= rectf[3];
- rectf[2] /= rectf[3];
+ RenderLayer *rlpp[RE_MAX_OSA];
+ int y, sample, totsample;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ for(sample= 0; sample<totsample; sample++) {
+ float *rectf= rlpp[sample]->rectf;
+
+ for(y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
+ if(rectf[3] >= 1.0f);
+ else if(rectf[3] > 0.0f) {
+ rectf[0] /= rectf[3];
+ rectf[1] /= rectf[3];
+ rectf[2] /= rectf[3];
+ }
}
}
}
/* adds only alpha values */
-void edge_enhance_tile(RenderPart *pa, float *rectf)
+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;
@@ -693,13 +950,13 @@ void edge_enhance_tile(RenderPart *pa, float *rectf)
float *rf;
/* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */
- rz= pa->rectz;
+ rz= rectz;
if(rz==NULL) return;
for(y=0; y<pa->recty; y++)
for(x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4;
- rz1= pa->rectz;
+ rz1= rectz;
rz2= rz1+pa->rectx;
rz3= rz2+pa->rectx;
@@ -739,7 +996,7 @@ void edge_enhance_tile(RenderPart *pa, float *rectf)
}
/* shift back zbuf values, we might need it still */
- rz= pa->rectz;
+ rz= rectz;
for(y=0; y<pa->recty; y++)
for(x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4;
@@ -748,20 +1005,24 @@ void edge_enhance_tile(RenderPart *pa, float *rectf)
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;
-
- fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
- if(fp==NULL) return;
+ int a, sample, totsample;
- for(a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
- if(fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f;
-}
+ totsample= get_sample_layers(pa, rl, rlpp);
+ for(sample= 0; sample<totsample; sample++) {
+ fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR);
+ 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)
{
- long *rd= pa->rectdaps;
+ intptr_t *rd= pa->rectdaps;
unsigned short *solidmask, *sp;
int x;
@@ -826,25 +1087,25 @@ void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data)
{
ZbufSolidData *sdata= (ZbufSolidData*)data;
ListBase *lb= sdata->psmlist;
- long *rd= pa->rectdaps;
+ intptr_t *rd= pa->rectdaps;
int *ro= zspan->recto;
int *rp= zspan->rectp;
int *rz= zspan->rectz;
+ 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++) {
+ for(x=0; x<pa->rectx; x++, rd++, rp++, ro++, rz++, rm++) {
if(*rp) {
- addps(lb, rd, *ro, *rp, *(rz+x), mask);
+ addps(lb, rd, *ro, *rp, *rz, (zspan->rectmask)? *rm: 0, mask);
}
}
- rz+= pa->rectx;
}
if(sdata->rl->layflag & SCE_LAY_EDGE)
if(R.r.mode & R_EDGE)
- edge_enhance_tile(pa, sdata->edgerect);
+ edge_enhance_tile(pa, sdata->edgerect, zspan->rectz);
}
/* main call for shading Delta Accum, for OSA */
@@ -861,12 +1122,13 @@ void zbufshadeDA_tile(RenderPart *pa)
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) {
-
+ 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(long)*pa->rectx*pa->recty+4, "zbufDArectd");
+ 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)
@@ -879,7 +1141,7 @@ void zbufshadeDA_tile(RenderPart *pa)
sdata.rl= rl;
sdata.psmlist= &psmlist;
sdata.edgerect= edgerect;
- zbuffer_solid(pa, rl->lay, rl->layflag, make_pixelstructs, &sdata);
+ zbuffer_solid(pa, rl, make_pixelstructs, &sdata);
if(R.test_break()) break;
}
@@ -895,108 +1157,74 @@ void zbufshadeDA_tile(RenderPart *pa)
/* halo before ztra, because ztra fills in zbuffer now */
if(R.flag & R_HALO)
if(rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl->rectf, rl->lay);
+ halo_tile(pa, rl);
/* transp layer */
- if(R.flag & R_ZTRA) {
- if(rl->layflag & SCE_LAY_ZTRA) {
- 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, rl->rectf);
- ztramask= zbuffer_transp_shade(pa, rl, rl->rectf);
- SWAP(float *, rl->acolrect, rl->rectf);
-
- /* 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= rl->rectf; float *acol= rl->acolrect;
- int x;
+ 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, rl->rectf, &psmlist);
+ }
+ else {
+ unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
- 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);
+ /* 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, rl->rectf);
+ ztramask= zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist);
+ SWAP(float *, rl->acolrect, rl->rectf);
+
+ /* 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= rl->rectf; 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= rl->rectf; float *acol= rl->acolrect;
- int x;
- for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
- addAlphaOverFloat(fcol, acol);
+ else {
+ float *fcol= rl->rectf; 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);
- }
- }
-
- /* strand rendering */
- if((rl->layflag & SCE_LAY_STRAND) && R.totstrand) {
- float *fcol, *scol;
- unsigned short *strandmask, *solidmask= NULL; /* 16 bits, MAX_OSA */
- int x;
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->scolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "strand layer");
-
- /* swap for live updates, and it is used in zbuf.c!!! */
- SWAP(float*, rl->scolrect, rl->rectf);
- strandmask= zbuffer_strands_shade(&R, pa, rl, rl->rectf);
- SWAP(float*, rl->scolrect, rl->rectf);
-
- /* zbuffer strands only returns strandmask if there's solid rendered */
- if(strandmask)
- solidmask= make_solid_mask(pa);
-
- if(strandmask && solidmask) {
- unsigned short *sps= solidmask, *spz= strandmask;
- unsigned short fullmask= (1<<R.osa)-1;
-
- fcol= rl->rectf; scol= rl->scolrect;
- for(x=pa->rectx*pa->recty; x>0; x--, scol+=4, fcol+=4, sps++, spz++) {
- if(*sps == fullmask)
- addAlphaOverFloat(fcol, scol);
- else
- addAlphaOverFloatMask(fcol, scol, *sps, *spz);
+ if(solidmask) MEM_freeN(solidmask);
+ if(ztramask) MEM_freeN(ztramask);
}
}
- else {
- fcol= rl->rectf; scol= rl->scolrect;
- for(x=pa->rectx*pa->recty; x>0; x--, scol+=4, fcol+=4)
- addAlphaOverFloat(fcol, scol);
- }
-
- if(solidmask) MEM_freeN(solidmask);
- if(strandmask) MEM_freeN(strandmask);
}
+ /* 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->rectf);
+ sky_tile(pa, rl);
/* extra layers */
if(rl->layflag & SCE_LAY_EDGE)
if(R.r.mode & R_EDGE)
edge_enhance_add(pa, rl->rectf, edgerect);
- if(rl->passflag & SCE_PASS_Z)
- convert_zbuf_to_distbuf(pa, rl);
-
if(rl->passflag & SCE_PASS_VECTOR)
reset_sky_speed(pa, rl);
/* de-premul alpha */
if(R.r.alphamode & R_ALPHAKEY)
- convert_to_key_alpha(pa, rl->rectf);
+ convert_to_key_alpha(pa, rl);
/* free stuff within loop! */
MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
@@ -1004,6 +1232,11 @@ void zbufshadeDA_tile(RenderPart *pa)
if(edgerect) MEM_freeN(edgerect);
edgerect= NULL;
+
+ if(pa->rectmask) {
+ MEM_freeN(pa->rectmask);
+ pa->rectmask= NULL;
+ }
}
/* free all */
@@ -1028,7 +1261,6 @@ void zbufshade_tile(RenderPart *pa)
RenderLayer *rl;
PixStr ps;
float *edgerect= NULL;
- int addpassflag;
/* fake pixel struct, to comply to osa render */
ps.next= NULL;
@@ -1040,12 +1272,13 @@ void zbufshade_tile(RenderPart *pa)
pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
for(rl= rr->layers.first; rl; rl= rl->next) {
-
+ 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);
- addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
- zbuffer_solid(pa, rl->lay, rl->layflag, NULL, NULL);
+ zbuffer_solid(pa, rl, NULL, NULL);
if(!R.test_break()) { /* NOTE: this if() is not consistant */
@@ -1053,7 +1286,7 @@ void zbufshade_tile(RenderPart *pa)
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);
+ edge_enhance_tile(pa, edgerect, pa->rectz);
}
}
@@ -1072,6 +1305,9 @@ void zbufshade_tile(RenderPart *pa)
/* 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++) {
@@ -1083,14 +1319,8 @@ void zbufshade_tile(RenderPart *pa)
ps.facenr= *rp;
ps.z= *rz;
if(shade_samples(&ssamp, &ps, x, y)) {
- QUATCOPY(fcol, ssamp.shr[0].combined);
-
- if(!(fcol[0] == fcol[0]))
- printvecf("fudgecol", fcol);
-
- /* passes */
- if(addpassflag)
- add_passes(rl, offs, ssamp.shi, ssamp.shr);
+ /* combined and passes */
+ add_passes(rl, offs, ssamp.shi, ssamp.shr);
}
}
}
@@ -1098,6 +1328,9 @@ void zbufshade_tile(RenderPart *pa)
if(R.test_break()) break;
}
+ if(R.occlusiontree)
+ free_occ_samples(&R, pa);
+
if(R.r.mode & R_SHADOW)
ISB_free(pa);
}
@@ -1114,10 +1347,10 @@ void zbufshade_tile(RenderPart *pa)
/* halo before ztra, because ztra fills in zbuffer now */
if(R.flag & R_HALO)
if(rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl->rectf, rl->lay);
+ halo_tile(pa, rl);
- if(R.flag & R_ZTRA) {
- if(rl->layflag & SCE_LAY_ZTRA) {
+ if(R.flag & R_ZTRA || R.totstrand) {
+ if(rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
float *fcol, *acol;
int x;
@@ -1126,7 +1359,7 @@ void zbufshade_tile(RenderPart *pa)
/* swap for live updates */
SWAP(float *, rl->acolrect, rl->rectf);
- zbuffer_transp_shade(pa, rl, rl->rectf);
+ zbuffer_transp_shade(pa, rl, rl->rectf, NULL);
SWAP(float *, rl->acolrect, rl->rectf);
fcol= rl->rectf; acol= rl->acolrect;
@@ -1135,28 +1368,14 @@ void zbufshade_tile(RenderPart *pa)
}
}
}
-
- /* strand rendering */
- if((rl->layflag & SCE_LAY_STRAND) && R.totstrand) {
- float *fcol, *scol;
- int x;
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->scolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "strand layer");
-
- /* swap for live updates */
- SWAP(float*, rl->scolrect, rl->rectf);
- zbuffer_strands_shade(&R, pa, rl, rl->rectf);
- SWAP(float*, rl->scolrect, rl->rectf);
-
- fcol= rl->rectf; scol= rl->scolrect;
- for(x=pa->rectx*pa->recty; x>0; x--, scol+=4, fcol+=4)
- addAlphaOverFloat(fcol, scol);
- }
+
+ /* 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->rectf);
+ sky_tile(pa, rl);
if(!R.test_break()) {
if(rl->layflag & SCE_LAY_EDGE)
@@ -1164,18 +1383,20 @@ void zbufshade_tile(RenderPart *pa)
edge_enhance_add(pa, rl->rectf, edgerect);
}
- if(rl->passflag & SCE_PASS_Z)
- convert_zbuf_to_distbuf(pa, rl);
-
if(rl->passflag & SCE_PASS_VECTOR)
reset_sky_speed(pa, rl);
/* de-premul alpha */
if(R.r.alphamode & R_ALPHAKEY)
- convert_to_key_alpha(pa, rl->rectf);
+ convert_to_key_alpha(pa, rl);
if(edgerect) MEM_freeN(edgerect);
edgerect= NULL;
+
+ if(pa->rectmask) {
+ MEM_freeN(pa->rectmask);
+ pa->rectmask= NULL;
+ }
}
/* display active layer */
@@ -1207,9 +1428,9 @@ static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z)
return;
if(pa->rectall) {
- long *rs= pa->rectall + pa->rectx*y + x;
+ intptr_t *rs= pa->rectall + pa->rectx*y + x;
- addps(&handle->psmlist, rs, obi, facenr, z, 0);
+ addps(&handle->psmlist, rs, obi, facenr, z, 0, 0);
handle->totps++;
}
if(pa->rectz) {
@@ -1244,10 +1465,10 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
{
ShadeInput *shi= ssamp->shi;
ShadeResult shr;
- float texfac, orthoarea, nor[3];
+ float texfac, orthoarea, nor[3], alpha, sx, sy;
/* cache for shadow */
- shi->samplenr++;
+ shi->samplenr= R.shadowsamplenr[shi->thread]++;
if(quad)
shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
@@ -1255,8 +1476,8 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
/* center pixel */
- x += 0.5f;
- y += 0.5f;
+ 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
@@ -1265,13 +1486,13 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
shi->osatex= 1;
VECCOPY(nor, shi->facenor);
- calc_view_vector(shi->facenor, x, y);
+ calc_view_vector(shi->facenor, sx, sy);
Normalize(shi->facenor);
- shade_input_set_viewco(shi, x, y, z);
+ shade_input_set_viewco(shi, x, y, sx, sy, z);
orthoarea= VecLength(shi->dxco)*VecLength(shi->dyco);
VECCOPY(shi->facenor, nor);
- shade_input_set_viewco(shi, x, y, z);
+ shade_input_set_viewco(shi, x, y, sx, sy, z);
*area= VecLength(shi->dxco)*VecLength(shi->dyco);
*area= MIN2(*area, 2.0f*orthoarea);
@@ -1310,16 +1531,8 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
/* texture blending */
texfac= shi->mat->sss_texfac;
- if(texfac == 0.0f) {
- if(shr.col[0]!=0.0f) color[0] /= shr.col[0];
- if(shr.col[1]!=0.0f) color[1] /= shr.col[1];
- if(shr.col[2]!=0.0f) color[2] /= shr.col[2];
- }
- else if(texfac != 1.0f) {
- if(shr.col[0]!=0.0f) color[0] *= pow(shr.col[0], texfac)/shr.col[0];
- if(shr.col[1]!=0.0f) color[1] *= pow(shr.col[1], texfac)/shr.col[1];
- if(shr.col[2]!=0.0f) color[2] *= pow(shr.col[2], texfac)/shr.col[2];
- }
+ alpha= shr.combined[3];
+ *area *= alpha;
}
static void zbufshade_sss_free(RenderPart *pa)
@@ -1343,15 +1556,15 @@ void zbufshade_sss_tile(RenderPart *pa)
ShadeSample ssamp;
ZBufSSSHandle handle;
RenderResult *rr= pa->result;
- RenderLayer *rl= rr->layers.first;
+ RenderLayer *rl;
VlakRen *vlr;
Material *mat= re->sss_mat;
- float (*co)[3], (*color)[3], *area, *fcol= rl->rectf;
+ float (*co)[3], (*color)[3], *area, *fcol;
int x, y, seed, quad, totpoint, display = !(re->r.scemode & R_PREVIEWBUTS);
- int *ro, *rz, *rp, *rbo, *rbz, *rbp;
+ int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay;
#if 0
PixStr *ps;
- long *rs;
+ intptr_t *rs;
int z;
#endif
@@ -1363,7 +1576,7 @@ void zbufshade_sss_tile(RenderPart *pa)
handle.psmlist.first= handle.psmlist.last= NULL;
addpsmain(&handle.psmlist);
- pa->rectall= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "rectall");
+ 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");
@@ -1373,13 +1586,34 @@ void zbufshade_sss_tile(RenderPart *pa)
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 |= rl->lay;
+ 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);
+ ssamp.shi[0].mat_override= NULL;
+ ssamp.shi[0].light_override= NULL;
+ lay= ssamp.shi[0].lay;
+
/* create the pixelstrs to be used later */
- zbuffer_sss(pa, rl->lay, &handle, addps_sss);
+ zbuffer_sss(pa, lay, &handle, addps_sss);
if(handle.totps==0) {
zbufshade_sss_free(pa);
return;
}
+
+ fcol= rl->rectf;
co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
@@ -1391,14 +1625,6 @@ void zbufshade_sss_tile(RenderPart *pa)
ISB_create(pa, NULL);
#endif
- /* setup shade sample with correct passes */
- memset(&ssamp, 0, sizeof(ssamp));
- shade_sample_initialize(&ssamp, pa, rl);
- ssamp.shi[0].passflag= SCE_PASS_DIFFUSE|SCE_PASS_AO|SCE_PASS_RADIO;
- ssamp.shi[0].passflag |= SCE_PASS_RGBA;
- ssamp.shi[0].combinedflag= ~(SCE_PASS_SPEC);
- ssamp.tot= 1;
-
if(display) {
/* initialize scanline updates for main thread */
rr->renrect.ymin= 0;
@@ -1563,8 +1789,8 @@ static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* pos
dist= xsq+ysq;
if(dist<har->radsq) {
- shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec);
- addalphaAddfacFloat(rtf, colf, har->add);
+ if(shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec))
+ addalphaAddfacFloat(rtf, colf, har->add);
}
rtf+=4;
}
@@ -1701,6 +1927,8 @@ void add_halo_flare(Render *re)
void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr)
{
static VlakRen vlr;
+ static ObjectRen obr;
+ static ObjectInstanceRen obi;
/* init */
if(re) {
@@ -1708,11 +1936,16 @@ void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr)
/* fake render face */
memset(&vlr, 0, sizeof(VlakRen));
- vlr.lay= -1;
+ memset(&obr, 0, sizeof(ObjectRen));
+ memset(&obi, 0, sizeof(ObjectInstanceRen));
+ obr.lay= -1;
+ obi.obr= &obr;
return;
}
shi->vlr= &vlr;
+ shi->obr= &obr;
+ shi->obi= &obi;
if(shi->mat->nodetree && shi->mat->use_nodes)
ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
@@ -1727,7 +1960,6 @@ void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr)
/* ************************* bake ************************ */
-#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
typedef struct BakeShade {
ShadeSample ssamp;
@@ -1745,8 +1977,81 @@ typedef struct BakeShade {
unsigned int *rect;
float *rect_float;
+
+ int usemask;
+ char *rect_mask; /* bake pixel mask */
+
+ float dxco[3], dyco[3];
} BakeShade;
+/* bake uses a char mask to know what has been baked */
+#define BAKE_MASK_NULL 0
+#define BAKE_MASK_MARGIN 1
+#define BAKE_MASK_BAKED 2
+static void bake_mask_filter_extend( char *mask, int width, int height )
+{
+ char *row1, *row2, *row3;
+ int rowlen, x, y;
+ char *temprect;
+
+ rowlen= width;
+
+ /* make a copy, to prevent flooding */
+ temprect= MEM_dupallocN(mask);
+
+ for(y=1; y<=height; y++) {
+ /* setup rows */
+ row1= (char *)(temprect + (y-2)*rowlen);
+ row2= row1 + rowlen;
+ row3= row2 + rowlen;
+ if(y==1)
+ row1= row2;
+ else if(y==height)
+ row3= row2;
+
+ for(x=0; x<rowlen; x++) {
+ if (mask[((y-1)*rowlen)+x]==0) {
+ if (*row1 || *row2 || *row3 || *(row1+1) || *(row3+1) ) {
+ mask[((y-1)*rowlen)+x] = BAKE_MASK_MARGIN;
+ } else if((x!=rowlen-1) && (*(row1+2) || *(row2+2) || *(row3+2)) ) {
+ mask[((y-1)*rowlen)+x] = BAKE_MASK_MARGIN;
+ }
+ }
+
+ if(x!=0) {
+ row1++; row2++; row3++;
+ }
+ }
+ }
+ MEM_freeN(temprect);
+}
+
+static void bake_mask_clear( ImBuf *ibuf, char *mask, char val )
+{
+ int x,y;
+ if (ibuf->rect_float) {
+ for(x=0; x<ibuf->x; x++) {
+ for(y=0; y<ibuf->y; y++) {
+ if (mask[ibuf->x*y + x] == val) {
+ float *col= ibuf->rect_float + 4*(ibuf->x*y + x);
+ col[0] = col[1] = col[2] = col[3] = 0.0f;
+ }
+ }
+ }
+
+ } else {
+ /* char buffer */
+ for(x=0; x<ibuf->x; x++) {
+ for(y=0; y<ibuf->y; y++) {
+ if (mask[ibuf->x*y + x] == val) {
+ char *col= (char *)(ibuf->rect + ibuf->x*y + x);
+ col[0] = col[1] = col[2] = col[3] = 0;
+ }
+ }
+ }
+ }
+}
+
static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int isect, int x, int y, float u, float v)
{
if(isect) {
@@ -1768,23 +2073,28 @@ static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInpu
shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
}
- /* set up view vector */
- VECCOPY(shi->view, shi->co);
- Normalize(shi->view);
-
/* cache for shadow */
- shi->samplenr++;
+ 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 quad, int x, int y, float u, float v, float *tvn, float *ttang)
@@ -1800,12 +2110,20 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
if(bs->type==RE_BAKE_AO) {
ambient_occlusion(shi);
- ambient_occlusion_to_diffuse(shi, shr.combined);
+
+ if(R.r.bake_flag & R_BAKE_NORMALIZE)
+ VECCOPY(shr.combined, shi->ao)
+ else
+ ambient_occlusion_to_diffuse(shi, shr.combined);
}
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);
- shade_samples_do_AO(ssamp);
+ if(!ELEM3(bs->type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_SHADOW))
+ shade_samples_do_AO(ssamp);
if(shi->mat->nodetree && shi->mat->use_nodes) {
ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
@@ -1830,8 +2148,8 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
VECCOPY(mat[2], tvn);
}
else {
- VECCOPY(mat[0], shi->tang);
- Crossf(mat[1], shi->vn, shi->tang);
+ VECCOPY(mat[0], shi->nmaptang);
+ Crossf(mat[1], shi->vn, shi->nmaptang);
VECCOPY(mat[2], shi->vn);
}
@@ -1853,35 +2171,80 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
shr.combined[0]= shi->r;
shr.combined[1]= shi->g;
shr.combined[2]= shi->b;
+ shr.alpha = shi->alpha;
+ }
+ else if(bs->type==RE_BAKE_SHADOW) {
+ VECCOPY(shr.combined, shr.shad);
+ shr.alpha = shi->alpha;
}
}
- if(bs->rect) {
+ if(bs->rect_float) {
+ float *col= bs->rect_float + 4*(bs->rectx*y + x);
+ VECCOPY(col, shr.combined);
+ if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) {
+ col[3]= shr.alpha;
+ } else {
+ col[3]= 1.0;
+ }
+ }
+ else {
char *col= (char *)(bs->rect + bs->rectx*y + x);
col[0]= FTOCHAR(shr.combined[0]);
col[1]= FTOCHAR(shr.combined[1]);
col[2]= FTOCHAR(shr.combined[2]);
- col[3]= 255;
+
+
+ if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) {
+ col[3]= FTOCHAR(shr.alpha);
+ } else {
+ col[3]= 255;
+ }
}
- else {
+
+ if (bs->rect_mask) {
+ bs->rect_mask[bs->rectx*y + x] = BAKE_MASK_BAKED;
+ }
+}
+
+static void bake_displacement(void *handle, ShadeInput *shi, float dist, int x, int y)
+{
+ BakeShade *bs= handle;
+ float disp;
+
+ if(R.r.bake_flag & R_BAKE_NORMALIZE && 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 = 0.5 + dist; /* alter the range from [-0.5,0.5] to [0,1]*/
+ }
+
+ if(bs->rect_float) {
float *col= bs->rect_float + 4*(bs->rectx*y + x);
- VECCOPY(col, shr.combined);
+ col[0] = col[1] = col[2] = disp;
col[3]= 1.0f;
+ } else {
+ char *col= (char *)(bs->rect + bs->rectx*y + x);
+ col[0]= FTOCHAR(disp);
+ col[1]= FTOCHAR(disp);
+ col[2]= FTOCHAR(disp);
+ col[3]= 255;
+ }
+ if (bs->rect_mask) {
+ bs->rect_mask[bs->rectx*y + x] = BAKE_MASK_BAKED;
}
}
-static int bake_check_intersect(Isect *is, RayFace *face)
+static int bake_check_intersect(Isect *is, int ob, RayFace *face)
{
- VlakRen *vlr = (VlakRen*)face;
BakeShade *bs = (BakeShade*)is->userdata;
/* no direction checking for now, doesn't always improve the result
* (INPR(shi->facenor, bs->dir) > 0.0f); */
- return (vlr->obr->ob != bs->actob);
+ return (R.objectinstance[ob].obr->ob != bs->actob);
}
-static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *dir, float sign, float *hitco)
+static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
{
float maxdist;
int hit;
@@ -1890,7 +2253,9 @@ static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *dir, float
if(R.r.bake_maxdist > 0.0f)
maxdist= R.r.bake_maxdist;
else
- maxdist= RE_ray_tree_max_size(R.raytree);
+ maxdist= RE_ray_tree_max_size(R.raytree) + R.r.bake_biasdist;
+
+ VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);
isect->end[0] = isect->start[0] + dir[0]*maxdist*sign;
isect->end[1] = isect->start[1] + dir[1]*maxdist*sign;
@@ -1901,11 +2266,62 @@ static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *dir, float
hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+
+ *dist= VecLenf(start, hitco);
}
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(fabs(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) {
+ Mat3MulVecfl(bs->obi->nmat, bs->dxco);
+ Mat3MulVecfl(bs->obi->nmat, bs->dyco);
+ }
+}
+
static void do_bake_shade(void *handle, int x, int y, float u, float v)
{
BakeShade *bs= handle;
@@ -1943,52 +2359,64 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
if(obi->flag & R_TRANSFORMED)
Mat4MulVecfl(obi->mat, shi->co);
+ VECCOPY(shi->dxco, bs->dxco);
+ VECCOPY(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);
VECCOPY(tvn, shi->vn);
- VECCOPY(ttang, shi->tang);
+ VECCOPY(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];
- int hit, sign;
+ 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;
-
+
VECCOPY(bs->dir, shi->vn);
-
+
for(sign=-1; sign<=1; sign+=2) {
memset(&isec, 0, sizeof(isec));
- VECCOPY(isec.start, shi->co);
isec.mode= RE_RAY_MIRROR;
isec.faceorig= (RayFace*)vlr;
isec.oborig= RAY_OBJECT_SET(&R, obi);
isec.userdata= bs;
-
- if(bake_intersect_tree(R.raytree, &isec, shi->vn, sign, co)) {
+
+ if(bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
if(!hit || VecLenf(shi->co, co) < VecLenf(shi->co, minco)) {
minisec= isec;
+ mindist= dist;
VECCOPY(minco, co);
hit= 1;
+ dir = sign;
}
}
}
+ if (bs->type==RE_BAKE_DISPLACEMENT) {
+ 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) {
vlr= (VlakRen*)minisec.face;
obi= RAY_OBJECT_GET(&R, minisec.ob);
quad= (minisec.isect == 2);
VECCOPY(shi->co, minco);
-
+
u= -minisec.u;
v= -minisec.v;
bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
@@ -2025,7 +2453,7 @@ static int get_next_bake_face(BakeShade *bs)
vlr= RE_findOrAddVlak(obr, v);
if((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
- tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
+ tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
if(tface && tface->tpage) {
Image *ima= tface->tpage;
@@ -2079,7 +2507,7 @@ 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->actmtface, NULL, 0);
+ MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
Image *ima= tface->tpage;
float vec[4][2];
int a, i1, i2, i3;
@@ -2099,6 +2527,19 @@ static void shade_tface(BakeShade *bs)
bs->rect_float= bs->ibuf->rect_float;
bs->quad= 0;
+ if (bs->usemask) {
+ if (bs->ibuf->userdata==NULL) {
+ BLI_lock_thread(LOCK_CUSTOM1);
+ if (bs->ibuf->userdata==NULL) { /* since the thread was locked, its possible another thread alloced the value */
+ bs->ibuf->userdata = (void *)MEM_callocN(sizeof(char)*bs->rectx*bs->recty, "BakeMask");
+ bs->rect_mask= (char *)bs->ibuf->userdata;
+ }
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ } else {
+ bs->rect_mask= (char *)bs->ibuf->userdata;
+ }
+ }
+
/* get pixel level vertex coordinates */
for(a=0; a<4; a++) {
vec[a][0]= tface->uv[a][0]*(float)bs->rectx - 0.5f;
@@ -2108,10 +2549,12 @@ static void shade_tface(BakeShade *bs)
/* 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);
}
}
@@ -2140,8 +2583,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
BakeShade handles[BLENDER_MAX_THREADS];
ListBase threads;
Image *ima;
- int a, vdone=0;
-
+ int a, vdone=0, usemask=0;
+
/* initialize render global */
R= *re;
R.bakebuf= NULL;
@@ -2149,9 +2592,17 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
/* initialize static vars */
get_next_bake_face(NULL);
+ /* do we need a mask? */
+ if (re->r.bake_filter && (re->r.bake_flag & R_BAKE_CLEAR)==0)
+ usemask = 1;
+
/* baker uses this flag to detect if image was initialized */
- for(ima= G.main->image.first; ima; ima= ima->id.next)
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
ima->id.flag |= LIB_DOIT;
+ if (ibuf)
+ ibuf->userdata = NULL; /* use for masking if needed */
+ }
BLI_init_threads(&threads, do_bake_thread, re->r.threads);
@@ -2161,7 +2612,12 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
memset(&handles[a], 0, sizeof(BakeShade));
handles[a].ssamp.shi[0].lay= re->scene->lay;
- handles[a].ssamp.shi[0].passflag= SCE_PASS_COMBINED;
+
+ 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.tot= 1;
@@ -2170,6 +2626,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
handles[a].actob= actob;
handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake");
+ handles[a].usemask = usemask;
+
BLI_insert_thread(&threads, &handles[a]);
}
@@ -2184,23 +2642,52 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
break;
}
- /* filter images */
+ /* filter and refresh images */
for(ima= G.main->image.first; ima; ima= ima->id.next) {
if((ima->id.flag & LIB_DOIT)==0) {
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
- for(a=0; a<re->r.bake_filter; a++)
- IMB_filter_extend(ibuf);
+ if (re->r.bake_filter) {
+ if (usemask) {
+ /* extend the mask +2 pixels from the image,
+ * this is so colors dont blend in from outside */
+ char *temprect;
+
+ for(a=0; a<re->r.bake_filter; a++)
+ bake_mask_filter_extend((char *)ibuf->userdata, ibuf->x, ibuf->y);
+
+ temprect = MEM_dupallocN(ibuf->userdata);
+
+ /* expand twice to clear this many pixels, so they blend back in */
+ bake_mask_filter_extend(temprect, ibuf->x, ibuf->y);
+ bake_mask_filter_extend(temprect, ibuf->x, ibuf->y);
+
+ /* clear all pixels in the margin*/
+ bake_mask_clear(ibuf, temprect, BAKE_MASK_MARGIN);
+ MEM_freeN(temprect);
+ }
+
+ for(a=0; a<re->r.bake_filter; a++) {
+ /*the mask, ibuf->userdata - can be null, in this case only zero alpha is used */
+ IMB_filter_extend(ibuf, (char *)ibuf->userdata);
+ }
+
+ if (ibuf->userdata) {
+ MEM_freeN(ibuf->userdata);
+ ibuf->userdata= NULL;
+ }
+ }
ibuf->userflags |= IB_BITMAPDIRTY;
+ if (ibuf->rect_float) IMB_rect_from_float(ibuf);
}
}
/* calculate return value */
- for(a=0; a<re->r.threads; a++) {
+ for(a=0; a<re->r.threads; a++) {
vdone+= handles[a].vdone;
zbuf_free_span(handles[a].zspan);
MEM_freeN(handles[a].zspan);
- }
+ }
BLI_end_threads(&threads);
return vdone;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 79c87252fc2..d44b49cc706 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -104,7 +104,10 @@
#define RE_MCOL_ELEMS 4
#define RE_UV_ELEMS 2
#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 12
float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify)
{
@@ -362,12 +365,43 @@ float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
}
+float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int verify)
+{
+ float *tangent;
+ int nr= vlak->index>>8;
+
+ tangent= obr->vlaknodes[nr].tangent;
+ if(tangent==NULL) {
+ if(verify)
+ tangent= obr->vlaknodes[nr].tangent= MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
+ else
+ return NULL;
+ }
+ return tangent + (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 *surfnor, *surfnor1, *tangent, *tangent1;
+ RadFace **radface, **radface1;
int i, index = vlr1->index;
char *name;
@@ -390,24 +424,31 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
VECCOPY(surfnor1, surfnor);
}
+ tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0);
+ if(tangent) {
+ tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1);
+ 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;
}
int RE_vlakren_get_normal(Render *re, ObjectInstanceRen *obi, VlakRen *vlr, float *nor)
{
- float xn, yn, zn, v1[3];
- float (*imat)[3]= obi->imat;
+ float v1[3], (*nmat)[3]= obi->nmat;
int flipped= 0;
if(obi->flag & R_TRANSFORMED) {
- xn= vlr->n[0];
- yn= vlr->n[1];
- zn= vlr->n[2];
+ VECCOPY(nor, vlr->n);
- /* 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;
+ Mat3MulVecfl(nmat, nor);
+ Normalize(nor);
}
else
VECCOPY(nor, vlr->n);
@@ -442,16 +483,16 @@ void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
DerivedMesh which stores the layers is freed */
CustomDataLayer *layer;
- int numlayers, i, mtfn, mcn;
+ int numtf = 0, numcol = 0, i, mtfn, mcn;
if (CustomData_has_layer(data, CD_MTFACE)) {
- numlayers= CustomData_number_of_layers(data, CD_MTFACE);
- obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numlayers, "mtfacenames");
+ numtf= CustomData_number_of_layers(data, CD_MTFACE);
+ obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames");
}
if (CustomData_has_layer(data, CD_MCOL)) {
- numlayers= CustomData_number_of_layers(data, CD_MCOL);
- obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numlayers, "mcolnames");
+ 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++) {
@@ -459,11 +500,12 @@ void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
if (layer->type == CD_MTFACE) {
strcpy(obr->mtface[mtfn++], layer->name);
- obr->actmtface= layer->active_rnd;
+ obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf);
+ obr->bakemtface= layer->active;
}
else if (layer->type == CD_MCOL) {
strcpy(obr->mcol[mcn++], layer->name);
- obr->actmcol= layer->active_rnd;
+ obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol);
}
}
}
@@ -516,7 +558,7 @@ float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify)
surfnor= obr->strandnodes[nr].surfnor;
if(surfnor==NULL) {
if(verify)
- surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
+ surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table");
else
return NULL;
}
@@ -536,7 +578,7 @@ float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name
float *uv= node->uv;
int size= (n+1)*256;
- node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "Strand uv");
+ node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table");
if(uv) {
size= node->totuv*256;
@@ -570,7 +612,7 @@ MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **nam
MCol *mcol= node->mcol;
int size= (n+1)*256;
- node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Strand mcol");
+ node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table");
if(mcol) {
size= node->totmcol*256;
@@ -599,13 +641,28 @@ float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand
simplify= obr->strandnodes[nr].simplify;
if(simplify==NULL) {
if(verify)
- simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify table");
+ 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)
{
@@ -616,7 +673,7 @@ float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int
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");
+ winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table");
}
else
return NULL;
@@ -671,14 +728,14 @@ StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
strandbuf->totvert= totvert;
strandbuf->obr= obr;
- BLI_addtail(&obr->strandbufs, strandbuf);
+ obr->strandbuf= strandbuf;
return strandbuf;
}
/* ------------------------------------------------------------------------ */
-ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex)
+ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay)
{
ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct");
@@ -687,11 +744,7 @@ ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, in
obr->par= par;
obr->index= index;
obr->psysindex= psysindex;
-
- if(!re->objecthash)
- re->objecthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
- if(!BLI_ghash_lookup(re->objecthash, ob))
- BLI_ghash_insert(re->objecthash, ob, obr);
+ obr->lay= lay;
return obr;
}
@@ -737,6 +790,10 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes[a].mcol);
if(vlaknodes[a].surfnor)
MEM_freeN(vlaknodes[a].surfnor);
+ if(vlaknodes[a].tangent)
+ MEM_freeN(vlaknodes[a].tangent);
+ if(vlaknodes[a].radface)
+ MEM_freeN(vlaknodes[a].radface);
}
MEM_freeN(vlaknodes);
@@ -761,6 +818,8 @@ void free_renderdata_strandnodes(StrandTableNode *strandnodes)
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);
@@ -802,9 +861,12 @@ void free_renderdata_tables(Render *re)
obr->strandnodeslen= 0;
}
- for(strandbuf=obr->strandbufs.first; strandbuf; strandbuf=strandbuf->next)
+ strandbuf= obr->strandbuf;
+ if(strandbuf) {
if(strandbuf->vert) MEM_freeN(strandbuf->vert);
- BLI_freelistN(&obr->strandbufs);
+ if(strandbuf->bound) MEM_freeN(strandbuf->bound);
+ MEM_freeN(strandbuf);
+ }
if(obr->mtface)
MEM_freeN(obr->mtface);
@@ -822,27 +884,15 @@ void free_renderdata_tables(Render *re)
re->totinstance= 0;
re->instancetable.first= re->instancetable.last= NULL;
}
- else {
- BLI_freelistN(&re->instancetable);
-
- if(re->objecthash) {
- BLI_ghash_free(re->objecthash, NULL, NULL);
- re->objecthash= NULL;
- }
- }
if(re->sortedhalos) {
MEM_freeN(re->sortedhalos);
re->sortedhalos= NULL;
}
- if(re->strandbuckets) {
- free_buckets(re->strandbuckets);
- re->strandbuckets= NULL;
- }
-
BLI_freelistN(&re->customdata_names);
BLI_freelistN(&re->objecttable);
+ BLI_freelistN(&re->instancetable);
}
/* ------------------------------------------------------------------------ */
@@ -1257,13 +1307,11 @@ void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4],
}
}
-
- project_strands(re, projectfunc, do_pano, do_buckets);
}
/* ------------------------------------------------------------------------- */
-void RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[][4])
+ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[][4], int lay)
{
ObjectInstanceRen *obi;
float mat3[3][3];
@@ -1274,15 +1322,19 @@ void RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, i
obi->par= par;
obi->index= index;
obi->psysindex= psysindex;
+ obi->lay= lay;
if(mat) {
Mat4CpyMat4(obi->mat, mat);
Mat3CpyMat4(mat3, mat);
- Mat3Inv(obi->imat, mat3);
+ Mat3Inv(obi->nmat, mat3);
+ Mat3Transp(obi->nmat);
obi->flag |= R_DUPLI_TRANSFORMED;
}
BLI_addtail(&re->instancetable, obi);
+
+ return obi;
}
void RE_makeRenderInstances(Render *re)
@@ -1301,15 +1353,6 @@ void RE_makeRenderInstances(Render *re)
for(oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
*obi= *oldobi;
- if(!obi->obr) {
- /* dupli objects are created after object instances, so they were
- * stored in a object -> objectren hash, we do lookup of the actual
- * pointer here */
- if(re->objecthash && (obi->obr=BLI_ghash_lookup(re->objecthash, obi->ob)))
- while(obi->obr && obi->obr->psysindex != obi->psysindex)
- obi->obr= obi->obr->next;
- }
-
if(obi->obr) {
obi->prev= obi->next= NULL;
BLI_addtail(&newlist, obi);
@@ -1319,11 +1362,44 @@ void RE_makeRenderInstances(Render *re)
re->totinstance--;
}
- if(re->objecthash) {
- BLI_ghash_free(re->objecthash, NULL, NULL);
- re->objecthash= NULL;
- }
BLI_freelistN(&re->instancetable);
re->instancetable= newlist;
}
+int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4])
+{
+ float mat[4][4], vec[4];
+ int a, fl, flag= -1;
+
+ Mat4CpyMat4(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;
+ Mat4MulVec4fl(mat, vec);
+
+ fl= 0;
+ if(bounds) {
+ if(vec[0] > bounds[1]*vec[3]) fl |= 1;
+ if(vec[0]< bounds[0]*vec[3]) fl |= 2;
+ if(vec[1] > bounds[3]*vec[3]) fl |= 4;
+ if(vec[1]< bounds[2]*vec[3]) fl |= 8;
+ }
+ else {
+ if(vec[0] < -vec[3]) fl |= 1;
+ if(vec[0] > vec[3]) fl |= 2;
+ if(vec[1] < -vec[3]) fl |= 4;
+ if(vec[1] > vec[3]) fl |= 8;
+ }
+ if(vec[2] < -vec[3]) fl |= 16;
+ 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
index 8e37606cdf9..c53a2b68c9c 100644
--- a/source/blender/render/intern/source/shadbuf.c
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -34,6 +34,7 @@
#include "DNA_material_types.h"
#include "BKE_global.h"
+#include "BKE_scene.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
@@ -54,7 +55,7 @@
/* XXX, could be better implemented... this is for endian issues
*/
-#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__hppa__) || defined (__BIG_ENDIAN__)
#define RCOMP 3
#define GCOMP 2
#define BCOMP 1
@@ -140,10 +141,11 @@ static float *give_jitter_tab(int samp)
}
-static void make_jitter_weight_tab(ShadBuf *shb, short filtertype)
+static void make_jitter_weight_tab(Render *re, ShadBuf *shb, short filtertype)
{
float *jit, totw= 0.0f;
- int a, tot=shb->samp*shb->samp;
+ 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");
@@ -169,7 +171,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
{
ShadSampleBuf *shsample;
float dist;
- unsigned long *ztile;
+ uintptr_t *ztile;
int *rz, *rz1, verg, verg1, size= shb->size;
int a, x, y, minx, miny, byt1, byt2;
char *rc, *rcline, *ctile, *zt;
@@ -177,10 +179,10 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
shsample= MEM_mallocN( sizeof(ShadSampleBuf), "shad sample buf");
BLI_addtail(&shb->buffers, shsample);
- shsample->zbuf= MEM_mallocN( sizeof(unsigned long)*(size*size)/256, "initshadbuf2");
+ shsample->zbuf= MEM_mallocN( sizeof(uintptr_t)*(size*size)/256, "initshadbuf2");
shsample->cbuf= MEM_callocN( (size*size)/256, "initshadbuf3");
- ztile= (unsigned long *)shsample->zbuf;
+ ztile= (uintptr_t *)shsample->zbuf;
ctile= shsample->cbuf;
/* help buffer */
@@ -235,7 +237,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
}
if(byt1 && byt2) { /* only store byte */
*ctile= 1;
- *ztile= (unsigned long)MEM_mallocN(256+4, "tile1");
+ *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1");
rz= (int *)*ztile;
*rz= *rz1;
@@ -245,7 +247,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
}
else if(byt1) { /* only store short */
*ctile= 2;
- *ztile= (unsigned long)MEM_mallocN(2*256+4,"Tile2");
+ *ztile= (uintptr_t)MEM_mallocN(2*256+4,"Tile2");
rz= (int *)*ztile;
*rz= *rz1;
@@ -258,7 +260,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
}
else { /* store triple */
*ctile= 3;
- *ztile= (unsigned long)MEM_mallocN(3*256,"Tile3");
+ *ztile= (uintptr_t)MEM_mallocN(3*256,"Tile3");
zt= (char *)*ztile;
rc= rcline;
@@ -288,15 +290,19 @@ static void shadowbuf_autoclip(Render *re, LampRen *lar)
Material *ma= NULL;
float minz, maxz, vec[3], viewmat[4][4], obviewmat[4][4];
unsigned int lay = -1;
- int i, a, ok= 1;
+ int i, a, maxtotvert, ok= 1;
char *clipflag;
minz= 1.0e30f; maxz= -1.0e30f;
Mat4CpyMat4(viewmat, lar->shb->viewmat);
- if(lar->mode & LA_LAYER) lay= lar->lay;
+ if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
- clipflag= MEM_callocN(sizeof(char)*re->totvert, "autoclipflag");
+ maxtotvert= 0;
+ for(obr=re->objecttable.first; obr; obr=obr->next)
+ maxtotvert= MAX2(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) {
@@ -321,7 +327,7 @@ static void shadowbuf_autoclip(Render *re, LampRen *lar)
if((ma->mode & MA_SHADBUF)==0) ok= 0;
}
- if(ok && (vlr->lay & lay)) {
+ if(ok && (obi->lay & lay)) {
clipflag[vlr->v1->index]= 1;
clipflag[vlr->v2->index]= 1;
clipflag[vlr->v3->index]= 1;
@@ -402,8 +408,8 @@ void makeshadowbuf(Render *re, LampRen *lar)
if(ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY)) {
/* jitter, weights - not threadsafe! */
BLI_lock_thread(LOCK_CUSTOM1);
- shb->jit= give_jitter_tab(shb->samp);
- make_jitter_weight_tab(shb, lar->filtertype);
+ shb->jit= give_jitter_tab(get_render_shadow_samples(&re->r, shb->samp));
+ make_jitter_weight_tab(re, shb, lar->filtertype);
BLI_unlock_thread(LOCK_CUSTOM1);
shb->totbuf= lar->buffers;
@@ -536,7 +542,7 @@ void freeshadowbuf(LampRen *lar)
v= (shb->size*shb->size)/256;
for(shsample= shb->buffers.first; shsample; shsample= shsample->next) {
- long *ztile= shsample->zbuf;
+ intptr_t *ztile= shsample->zbuf;
char *ctile= shsample->cbuf;
for(b=0; b<v; b++, ztile++, ctile++)
@@ -630,7 +636,7 @@ static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int
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= (int) rz;
+ zsamp= GET_INT_FROM_POINTER(rz);
}
/* tricky stuff here; we use ints which can overflow easily with bias values */
@@ -648,11 +654,11 @@ static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int
/* the externally called shadow testing (reading) function */
/* return 1.0: no shadow at all */
-float testshadowbuf(ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp)
+float testshadowbuf(Render *re, ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp, float mat_bias)
{
ShadSampleBuf *shsample;
float fac, co[4], dx[3], dy[3], shadfac=0.0f;
- float xs1,ys1, siz, *jit, *weight, xres, yres;
+ float xs1,ys1, siz, *jit, *weight, xres, yres, biasf;
int xs, ys, zs, bias, *rz;
short a, num;
@@ -686,13 +692,16 @@ float testshadowbuf(ShadBuf *shb, float *rco, float *dxco, float *dyco, float in
zs= ((float)0x7FFFFFFF)*fac;
/* take num*num samples, increase area with fac */
- num= shb->samp*shb->samp;
+ num= get_render_shadow_samples(&re->r, shb->samp);
+ num= num*num;
fac= shb->soft;
+ 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)*shb->bias;
-
+ bias= (1.5f-inp*inp)*biasf;
+
if(num==1) {
for(shsample= shb->buffers.first; shsample; shsample= shsample->next)
shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
@@ -807,7 +816,7 @@ static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, i
else {
/* same as before */
/* still working code! (ton) */
- zsamp= (int) rz;
+ zsamp= GET_INT_FROM_POINTER(rz);
}
/* NO schadow when sampled at 'eternal' distance */
@@ -1511,7 +1520,7 @@ static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
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) lay= lar->lay;
+ 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);
@@ -1552,7 +1561,7 @@ static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha;
}
- if(ok && (vlr->lay & lay)) {
+ if(ok && (obi->lay & lay)) {
float hoco[4][4];
int c1, c2, c3, c4=0;
int d1, d2, d3, d4=0;
@@ -1743,7 +1752,7 @@ static void isb_make_buffer(RenderPart *pa, LampRen *lar)
ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */
ISBBranch root;
MemArena *memarena;
- long *rd;
+ intptr_t *rd;
int *recto, *rectp, x, y, sindex, sample, bsp_err=0;
/* storage for shadow, per thread */
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index f937218cdb6..476330152ec 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -31,6 +31,7 @@
#include "MTC_matrixops.h"
#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h"
@@ -129,7 +130,7 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
}
/* disable adding of sky for raytransp */
if(shi->mat->mode & MA_RAYTRANSP)
- if(shi->layflag & SCE_LAY_SKY)
+ if((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode==R_ADDSKY))
shr->alpha= 1.0f;
}
}
@@ -161,11 +162,16 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
}
/* MIST */
- if((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0 ) {
+ if((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0)) {
if(R.r.mode & R_ORTHO)
- alpha= mistfactor(-shi->co[2], shi->co);
+ shr->mist= mistfactor(-shi->co[2], shi->co);
else
- alpha= mistfactor(VecLength(shi->co), shi->co);
+ shr->mist= mistfactor(VecLength(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;
@@ -180,6 +186,8 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
}
else shr->combined[3]= 1.0f;
+ /* add z */
+ shr->z= -shi->co[2];
}
/* **************************************************************************** */
@@ -209,19 +217,6 @@ void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
}
}
-static void normal_transform(float imat[][3], float *nor)
-{
- float xn, yn, zn;
-
- xn= nor[0];
- yn= nor[1];
- zn= nor[2];
-
- 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;
-}
-
/* 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)
@@ -231,7 +226,7 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen
shi->vlr= vlr;
shi->obi= obi;
shi->obr= obi->obr;
-
+
shi->v1= vpp[i1];
shi->v2= vpp[i2];
shi->v3= vpp[i3];
@@ -261,9 +256,9 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen
VECCOPY(shi->n3, shi->v3->n);
if(obi->flag & R_TRANSFORMED) {
- normal_transform(obi->imat, shi->n1);
- normal_transform(obi->imat, shi->n2);
- normal_transform(obi->imat, shi->n3);
+ Mat3MulVecfl(obi->nmat, shi->n1);
+ Mat3MulVecfl(obi->nmat, shi->n2);
+ Mat3MulVecfl(obi->nmat, shi->n3);
}
if(!(vlr->flag & (R_NOPUNOFLIP|R_TANGENT))) {
@@ -348,10 +343,19 @@ void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spo
VECCOPY(shi->orignor, shi->facenor);
/* shade_input_set_normals equivalent */
- if(shi->mat->mode & MA_TANGENT_STR)
+ if(shi->mat->mode & MA_TANGENT_STR) {
VECCOPY(shi->vn, spoint->tan)
- else
- VECCOPY(shi->vn, spoint->nor)
+ }
+ else {
+ float cross[3];
+
+ Crossf(cross, spoint->co, spoint->tan);
+ Crossf(shi->vn, cross, spoint->tan);
+ Normalize(shi->vn);
+
+ if(INPR(shi->vn, shi->view) < 0.0f)
+ VecMulf(shi->vn, -1.0f);
+ }
VECCOPY(shi->vno, shi->vn);
}
@@ -374,6 +378,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
if(mode & (MA_TANGENT_V|MA_NORMAP_TANG)) {
VECCOPY(shi->tang, spoint->tan);
+ VECCOPY(shi->nmaptang, spoint->tan);
}
if(mode & MA_STR_SURFDIFF) {
@@ -388,7 +393,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
shi->surfdist= 0.0f;
for(sv=strand->vert; sv!=svert; sv++)
shi->surfdist+=VecLenf(sv->co, (sv+1)->co);
- shi->surfdist += 0.5f*(spoint->strandco+1.0f)*VecLenf(sv->co, (sv+1)->co);
+ shi->surfdist += spoint->t*VecLenf(sv->co, (sv+1)->co);
}
}
@@ -422,7 +427,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
if(texco & TEXCO_STRAND) {
- shi->strand= spoint->strandco;
+ shi->strandco= spoint->strandco;
if(shi->osatex) {
shi->dxstrand= spoint->dtstrandco;
@@ -438,6 +443,8 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
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++) {
@@ -447,15 +454,15 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
shi->totcol++;
scol->name= name;
- scol->col[0]= cp[0]/255.0f;
- scol->col[1]= cp[1]/255.0f;
- scol->col[2]= cp[2]/255.0f;
+ scol->col[0]= cp[3]/255.0f;
+ scol->col[1]= cp[2]/255.0f;
+ scol->col[2]= cp[1]/255.0f;
}
if(shi->totcol) {
- shi->vcol[0]= shi->col[0].col[0];
- shi->vcol[1]= shi->col[0].col[1];
- shi->vcol[2]= shi->col[0].col[2];
+ 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];
}
else {
shi->vcol[0]= 0.0f;
@@ -488,7 +495,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
suv->dyuv[1]= 0.0f;
}
- if((mode & MA_FACETEXTURE) && i==0) {
+ if((mode & MA_FACETEXTURE) && i==obr->actmtface) {
if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) {
shi->vcol[0]= 1.0f;
shi->vcol[1]= 1.0f;
@@ -537,6 +544,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
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;
}
}
}
@@ -565,31 +573,25 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
}
-/* scanline pixel coordinates */
-/* requires set_triangle */
-void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z)
+/* 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, float *dxyview, float *co, float *dxco, float *dyco)
{
- float fac;
-
- /* currently in use for dithering (soft shadow), node preview, irregular shad */
- shi->xs= (int)(x);
- shi->ys= (int)(y);
+ /* returns not normalized, so is in viewplane coords */
+ calc_view_vector(view, x, y);
- calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */
-
- /* wire cannot use normal for calculating shi->co */
if(shi->mat->mode & MA_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(shi->co, x, y, z);
+ calc_renderco_ortho(co, x, y, z);
else
- calc_renderco_zbuf(shi->co, shi->view, z);
+ calc_renderco_zbuf(co, view, z);
}
else {
- float dface, v1[3];
+ /* for non-wire, intersect with the triangle to get the exact coord */
+ float fac, dface, v1[3];
VECCOPY(v1, shi->v1->co);
-
if(shi->obi->flag & R_TRANSFORMED)
Mat4MulVecfl(shi->obi->mat, v1);
@@ -601,72 +603,98 @@ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z)
float fx= 2.0f/(R.winx*R.winmat[0][0]);
float fy= 2.0f/(R.winy*R.winmat[1][1]);
- shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
- shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/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)
- shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2];
+ co[2]= (dface - shi->facenor[0]*co[0] - shi->facenor[1]*co[1])/shi->facenor[2];
else
- shi->co[2]= 0.0f;
+ co[2]= 0.0f;
- if(shi->osatex || (R.r.mode & R_SHADOW) ) {
- shi->dxco[0]= fx;
- shi->dxco[1]= 0.0f;
+ if(dxco && dyco) {
+ dxco[0]= fx;
+ dxco[1]= 0.0f;
if(shi->facenor[2]!=0.0f)
- shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2];
+ dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2];
else
- shi->dxco[2]= 0.0f;
+ dxco[2]= 0.0f;
- shi->dyco[0]= 0.0f;
- shi->dyco[1]= fy;
+ dyco[0]= 0.0f;
+ dyco[1]= fy;
if(shi->facenor[2]!=0.0f)
- shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2];
+ dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2];
else
- shi->dyco[2]= 0.0f;
+ dyco[2]= 0.0f;
- if( (shi->mat->texco & TEXCO_REFL) ) {
- if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f;
- shi->dxview= -R.viewdx*fac;
- shi->dyview= -R.viewdy*fac;
+ if(dxyview) {
+ if(co[2]!=0.0f) fac= 1.0f/co[2]; else fac= 0.0f;
+ dxyview[0]= -R.viewdx*fac;
+ dxyview[1]= -R.viewdy*fac;
}
}
}
else {
float div;
- div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2];
+ div= shi->facenor[0]*view[0] + shi->facenor[1]*view[1] + shi->facenor[2]*view[2];
if (div!=0.0f) fac= dface/div;
else fac= 0.0f;
- shi->co[0]= fac*shi->view[0];
- shi->co[1]= fac*shi->view[1];
- shi->co[2]= fac*shi->view[2];
+ co[0]= fac*view[0];
+ co[1]= fac*view[1];
+ co[2]= fac*view[2];
/* pixel dx/dy for render coord */
- if(shi->osatex || (R.r.mode & R_SHADOW) ) {
+ if(dxco && dyco) {
float u= dface/(div - R.viewdx*shi->facenor[0]);
float v= dface/(div - R.viewdy*shi->facenor[1]);
- shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u;
- shi->dxco[1]= shi->co[1]- (shi->view[1])*u;
- shi->dxco[2]= shi->co[2]- (shi->view[2])*u;
+ dxco[0]= co[0]- (view[0]-R.viewdx)*u;
+ dxco[1]= co[1]- (view[1])*u;
+ dxco[2]= co[2]- (view[2])*u;
- shi->dyco[0]= shi->co[0]- (shi->view[0])*v;
- shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v;
- shi->dyco[2]= shi->co[2]- (shi->view[2])*v;
+ dyco[0]= co[0]- (view[0])*v;
+ dyco[1]= co[1]- (view[1]-R.viewdy)*v;
+ dyco[2]= co[2]- (view[2])*v;
- if( (shi->mat->texco & TEXCO_REFL) ) {
+ if(dxyview) {
if(fac!=0.0f) fac= 1.0f/fac;
- shi->dxview= -R.viewdx*fac;
- shi->dyview= -R.viewdy*fac;
+ dxyview[0]= -R.viewdx*fac;
+ dxyview[1]= -R.viewdy*fac;
}
}
}
}
/* cannot normalize earlier, code above needs it at viewplane level */
- Normalize(shi->view);
+ Normalize(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);
}
/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
@@ -798,7 +826,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
int mode= shi->mode; /* or-ed result for all nodes */
short texco= shi->mat->texco;
- /* calculate dxno and tangents */
+ /* calculate dxno */
if(shi->vlr->flag & R_SMOOTH) {
if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) {
@@ -814,47 +842,68 @@ void shade_input_set_shade_texco(ShadeInput *shi)
shi->dyno[2]= dl*n3[2]-shi->dy_u*n1[2]-shi->dy_v*n2[2];
}
-
- /* qdn: normalmap tangent space */
- if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
- float *s1, *s2, *s3;
+ }
+
+ /* calc tangents */
+ if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
+ float *tangent, *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);
- 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]= (l*s3[0] - u*s1[0] - v*s2[0]);
- shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]);
- shi->tang[2]= (l*s3[2] - u*s1[2] - v*s2[2]);
+ 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)
- normal_transform(obi->imat, shi->tang);
+ Mat3MulVecfl(obi->nmat, shi->tang);
- /* qdn: normalize just in case */
Normalize(shi->tang);
+ VECCOPY(shi->nmaptang, shi->tang);
}
- else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
}
- }
- else {
- /* qdn: normalmap tangent space */
- if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
- /* qdn: flat faces have tangents too,
- could pick either one, using average here */
- float *s1 = RE_vertren_get_tangent(obr, v1, 0);
- float *s2 = RE_vertren_get_tangent(obr, v2, 0);
- float *s3 = RE_vertren_get_tangent(obr, v3, 0);
- if (s1 && s2 && s3) {
- shi->tang[0] = (s1[0] + s2[0] + s3[0]);
- shi->tang[1] = (s1[1] + s2[1] + s3[1]);
- shi->tang[2] = (s1[2] + s2[2] + s3[2]);
+
+ if(mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT) {
+ tangent= RE_vlakren_get_nmap_tangent(obr, shi->vlr, 0);
+
+ if(tangent) {
+ int j1= shi->i1, j2= shi->i2, j3= shi->i3;
+
+ vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
+
+ s1= &tangent[j1*3];
+ s2= &tangent[j2*3];
+ s3= &tangent[j3*3];
+
+ shi->nmaptang[0]= (tl*s3[0] - tu*s1[0] - tv*s2[0]);
+ shi->nmaptang[1]= (tl*s3[1] - tu*s1[1] - tv*s2[1]);
+ shi->nmaptang[2]= (tl*s3[2] - tu*s1[2] - tv*s2[2]);
if(obi->flag & R_TRANSFORMED)
- normal_transform(obi->imat, shi->tang);
+ Mat3MulVecfl(obi->nmat, shi->nmaptang);
- Normalize(shi->tang);
+ Normalize(shi->nmaptang);
}
- else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
}
}
@@ -864,7 +913,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
if(surfnor) {
VECCOPY(shi->surfnor, surfnor)
if(obi->flag & R_TRANSFORMED)
- normal_transform(obi->imat, shi->surfnor);
+ Mat3MulVecfl(obi->nmat, shi->surfnor);
}
else
VECCOPY(shi->surfnor, shi->vn)
@@ -919,6 +968,8 @@ void shade_input_set_shade_texco(ShadeInput *shi)
shi->dylo[2]= dl*o3[2]-shi->dy_u*o1[2]-shi->dy_v*o2[2];
}
}
+
+ VECCOPY(shi->duplilo, obi->dupliorco);
}
if(texco & TEXCO_GLOB) {
@@ -933,7 +984,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
if(texco & TEXCO_STRAND) {
- shi->strand= (l*v3->accum - u*v1->accum - v*v2->accum);
+ 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;
@@ -975,9 +1026,9 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
if(shi->totcol) {
- shi->vcol[0]= shi->col[0].col[0];
- shi->vcol[1]= shi->col[0].col[1];
- shi->vcol[2]= shi->col[0].col[2];
+ 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]= 1.0f;
}
else {
@@ -1033,6 +1084,10 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
+ 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];
@@ -1097,6 +1152,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
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;
}
}
}
@@ -1181,7 +1237,9 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
}
- }
+ } /* 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 in-initialized values are used
+ */
}
/* ****************** ShadeSample ************************************** */
@@ -1201,8 +1259,9 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in
shi->combinedflag= ~rl->pass_xor;
shi->mat_override= rl->mat_override;
shi->light_override= rl->light_override;
-
+// shi->rl= rl;
/* note shi.depth==0 means first hit, not raytracing */
+
}
/* initialize per part, not per pixel! */
@@ -1217,7 +1276,7 @@ void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl
memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
}
- ssamp->samplenr= 0; /* counter, detect shadow-reuse for shaders */
+ get_sample_layers(pa, rl, ssamp->rlpp);
}
/* Do AO or (future) GI */
@@ -1228,19 +1287,22 @@ void shade_samples_do_AO(ShadeSample *ssamp)
if(!(R.r.mode & R_SHADOW))
return;
- if(!(R.r.mode & R_RAYTRACE))
+ if(!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
return;
- if(R.wrld.mode & WO_AMB_OCC)
- if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_AO))
+ if(R.wrld.mode & WO_AMB_OCC) {
+ shi= &ssamp->shi[0];
+
+ if(((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & SCE_PASS_AO))
+ || (shi->passflag & SCE_PASS_AO))
for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++)
if(!(shi->mode & MA_SHLESS))
ambient_occlusion(shi); /* stores in shi->ao[] */
-
+ }
}
-static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
+void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
{
ShadeInput *shi;
float xs, ys;
@@ -1259,15 +1321,17 @@ static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, in
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 */
+ /* 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->samplenr= ssamp->samplenr++;
- shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+// 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);
shade_input_set_normals(shi);
@@ -1286,9 +1350,10 @@ static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, in
xs= (float)x + 0.5f;
ys= (float)y + 0.5f;
}
+
shi->mask= curmask;
- shi->samplenr= ssamp->samplenr++;
- shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+ 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++;
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index a08046da0da..4c627056c1d 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -43,6 +43,7 @@
#include "DNA_material_types.h"
/* local include */
+#include "occlusion.h"
#include "renderpipeline.h"
#include "render_types.h"
#include "pixelblending.h"
@@ -354,7 +355,7 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) {
if(lar->mode & LA_LAYER)
- if(shi->vlr && (lar->lay & shi->vlr->lay)==0)
+ if(shi->vlr && (lar->lay & shi->obi->lay)==0)
continue;
if((lar->lay & shi->lay)==0)
continue;
@@ -428,10 +429,6 @@ static float area_lamp_energy(float (*area)[3], float *co, float *vn)
double cross[4][3]; /* cross products of this */
double rad[4]; /* angles between vecs */
- /* extra test for dot */
- if ( INPR(co, vn) <= 0.0f)
- return 0.0f;
-
VECSUB(vec[0], co, area[0]);
VECSUB(vec[1], co, area[1]);
VECSUB(vec[2], co, area[2]);
@@ -480,8 +477,12 @@ static float area_lamp_energy_multisample(LampRen *lar, float *co, float *vn)
float *jitlamp= lar->jitter, vec[3];
float area[4][3], intens= 0.0f;
int a= lar->ray_totsamp;
-
-
+
+ /* test if co is behind lamp */
+ VECSUB(vec, co, lar->co);
+ if(INPR(vec, lar->vec) < 0.0f)
+ return 0.0f;
+
while(a--) {
vec[0]= jitlamp[0];
vec[1]= jitlamp[1];
@@ -1006,8 +1007,9 @@ static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec)
/* pure AO, check for raytrace and world should have been done */
void ambient_occlusion(ShadeInput *shi)
{
-
- if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
+ 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);
else
shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
@@ -1017,25 +1019,28 @@ void ambient_occlusion(ShadeInput *shi)
/* wrld mode was checked for */
void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
{
-
- if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
- float f= R.wrld.aoenergy*shi->mat->amb;
-
- if (R.wrld.aomix==WO_AOADDSUB) {
- diff[0] = 2.0f*shi->ao[0]-1.0f;
- diff[1] = 2.0f*shi->ao[1]-1.0f;
- diff[2] = 2.0f*shi->ao[2]-1.0f;
- }
- else if (R.wrld.aomix==WO_AOSUB) {
- diff[0] = shi->ao[0]-1.0f;
- diff[1] = shi->ao[1]-1.0f;
- diff[2] = shi->ao[2]-1.0f;
- }
- else {
- VECCOPY(diff, shi->ao);
+ if((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX) {
+ if(shi->mat->amb!=0.0f) {
+ float f= R.wrld.aoenergy*shi->mat->amb;
+
+ if (R.wrld.aomix==WO_AOADDSUB) {
+ diff[0] = 2.0f*shi->ao[0]-1.0f;
+ diff[1] = 2.0f*shi->ao[1]-1.0f;
+ diff[2] = 2.0f*shi->ao[2]-1.0f;
+ }
+ else if (R.wrld.aomix==WO_AOSUB) {
+ diff[0] = shi->ao[0]-1.0f;
+ diff[1] = shi->ao[1]-1.0f;
+ diff[2] = shi->ao[2]-1.0f;
+ }
+ else {
+ VECCOPY(diff, shi->ao);
+ }
+
+ VECMUL(diff, f);
}
-
- VECMUL(diff, f);
+ else
+ diff[0]= diff[1]= diff[2]= 0.0f;
}
else
diff[0]= diff[1]= diff[2]= 0.0f;
@@ -1054,7 +1059,7 @@ void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, i
if(lar->buftype==LA_SHADBUF_IRREGULAR)
shadfac[3]= ISB_getshadow(shi, lar->shb);
else
- shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp);
+ 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);
@@ -1174,15 +1179,18 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
{
Material *ma= shi->mat;
VlakRen *vlr= shi->vlr;
- float lv[3], lampdist, lacol[3], shadfac[4];
+ 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.0) return;
+ if (lar->energy == 0.0) 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;
/* optimisation, don't render fully black lamps */
if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
return;
@@ -1211,7 +1219,12 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
lacol[1]= lar->g;
lacol[2]= lar->b;
- if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol);
+ 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 */
@@ -1223,6 +1236,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
Crossf(nstrand, vn, cross);
blend= INPR(nstrand, shi->surfnor);
+ blend= 1.0f - blend;
CLAMP(blend, 0.0f, 1.0f);
VecLerpf(vnor, nstrand, shi->surfnor, blend);
@@ -1231,6 +1245,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
else {
Crossf(cross, lv, vn);
Crossf(vnor, cross, vn);
+ Normalize(vnor);
}
if(ma->strand_surfnor > 0.0f) {
@@ -1248,6 +1263,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
float cross[3];
Crossf(cross, lv, shi->tang);
Crossf(vnor, cross, shi->tang);
+ Normalize(vnor);
vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
vn= vnor;
}
@@ -1297,7 +1313,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
else is= inp; // Lambert
}
- /* i is diffuse */
+ /* 'is' is diffuse */
+ if((ma->shade_flag & MA_CUBIC) && is>0.0f && is<1.0f)
+ is= 3.0*is*is - 2.0*is*is*is; // nicer termination of shades
+
i= is*phongcorr;
if(i>0.0f) {
@@ -1328,13 +1347,13 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
if((lar->mode & LA_ONLYSHADOW) && i>0.0) {
shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
- shr->shad[0] -= shadfac[3]*shi->r;
- shr->shad[1] -= shadfac[3]*shi->g;
- shr->shad[2] -= shadfac[3]*shi->b;
+ 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]);
- shr->spec[0] -= shadfac[3]*shi->specr;
- shr->spec[1] -= shadfac[3]*shi->specg;
- shr->spec[2] -= shadfac[3]*shi->specb;
+ 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;
}
@@ -1352,6 +1371,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
else
add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
}
+ /* add light for colored shadow */
+ if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
+ add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]);
+ }
if(i_noshad>0.0f) {
if(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
if(ma->mode & MA_SHADOW_TRA)
@@ -1365,6 +1388,8 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
}
/* 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)));
@@ -1435,10 +1460,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
LampRen *lar;
GroupObject *go;
float inpr, lv[3];
- float *vn, *view, shadfac[4];
+ float *view, shadfac[4];
float ir, accum, visifac, lampdist;
- vn= shi->vn;
+
view= shi->view;
accum= ir= 0.0f;
@@ -1451,7 +1476,7 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
/* yafray: ignore shading by photonlights, not used in Blender */
if (lar->type==LA_YF_PHOTON) continue;
- if(lar->mode & LA_LAYER) if((lar->lay & shi->vlr->lay)==0) 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)) {
@@ -1501,8 +1526,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
}
}
+/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
static void wrld_exposure_correct(float *diff)
{
+
diff[0]= R.wrld.linfac*(1.0f-exp( diff[0]*R.wrld.logfac) );
diff[1]= R.wrld.linfac*(1.0f-exp( diff[1]*R.wrld.logfac) );
diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
@@ -1511,7 +1538,6 @@ static void wrld_exposure_correct(float *diff)
void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
{
Material *ma= shi->mat;
- VlakRen *vlr= shi->vlr;
int passflag= shi->passflag;
memset(shr, 0, sizeof(ShadeResult));
@@ -1541,6 +1567,24 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
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(shi->r, ma->sss_texfac);
+ shi->g= pow(shi->g, ma->sss_texfac);
+ shi->b= pow(shi->b, ma->sss_texfac);
+ shi->alpha= pow(shi->alpha, ma->sss_texfac);
+
+ shr->col[0]= pow(shr->col[0], ma->sss_texfac);
+ shr->col[1]= pow(shr->col[1], ma->sss_texfac);
+ shr->col[2]= pow(shr->col[2], ma->sss_texfac);
+ shr->col[3]= pow(shr->col[3], ma->sss_texfac);
+ }
+ }
}
if(ma->mode & MA_SHLESS) {
@@ -1565,7 +1609,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
/* AO pass */
if(R.wrld.mode & WO_AMB_OCC) {
- if(passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) {
+ if(((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & SCE_PASS_AO))
+ || (passflag & SCE_PASS_AO)) {
/* AO was calculated for scanline already */
if(shi->depth)
ambient_occlusion(shi);
@@ -1588,7 +1633,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
if (lar->type==LA_YF_PHOTON) continue;
/* test for lamp layer */
- if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue;
+ 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!) */
@@ -1606,20 +1651,26 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
if (shr->shad[2] < 0) shr->shad[2] = 0;
if(ma->sss_flag & MA_DIFF_SSS) {
- float sss[3], col[3], texfac= ma->sss_texfac;
+ 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) {
VECCOPY(col, shr->col);
+ VecMulf(col, invalpha);
}
else if(texfac==1.0f) {
col[0]= col[1]= col[2]= 1.0f;
+ VecMulf(col, invalpha);
}
else {
- col[0]= pow(shr->col[0], 1.0f-texfac);
- col[1]= pow(shr->col[1], 1.0f-texfac);
- col[2]= pow(shr->col[2], 1.0f-texfac);
+ VECCOPY(col, shr->col);
+ VecMulf(col, invalpha);
+ col[0]= pow(col[0], 1.0f-texfac);
+ col[1]= pow(col[1], 1.0f-texfac);
+ col[2]= pow(col[2], 1.0f-texfac);
}
shr->diff[0]= sss[0]*col[0];
@@ -1627,9 +1678,9 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shr->diff[2]= sss[2]*col[2];
if(shi->combinedflag & SCE_PASS_SHADOW) {
- shr->shad[0]= sss[0]*col[0];
- shr->shad[1]= sss[1]*col[1];
- shr->shad[2]= sss[2]*col[2];
+ shr->shad[0]= shr->diff[0];
+ shr->shad[1]= shr->diff[1];
+ shr->shad[2]= shr->diff[2];
}
}
}
@@ -1647,7 +1698,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
}
/* exposure correction */
- if(R.wrld.exp!=0.0f || R.wrld.range!=1.0f) {
+ 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);
}
@@ -1671,10 +1722,16 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shr->alpha= shi->alpha;
/* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */
- if(!(ma->sss_flag & MA_DIFF_SSS) || !has_sss_tree(&R, ma)) {
- shr->combined[0]+= shi->ambr + shi->r*shi->amb*shi->rad[0];
- shr->combined[1]+= shi->ambg + shi->g*shi->amb*shi->rad[1];
- shr->combined[2]+= shi->ambb + shi->b*shi->amb*shi->rad[2];
+ if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+ shr->combined[0]+= shi->ambr;
+ shr->combined[1]+= shi->ambg;
+ shr->combined[2]+= shi->ambb;
+
+ if(shi->combinedflag & SCE_PASS_RADIO) {
+ shr->combined[0]+= shi->r*shi->amb*shi->rad[0];
+ shr->combined[1]+= shi->g*shi->amb*shi->rad[1];
+ shr->combined[2]+= shi->b*shi->amb*shi->rad[2];
+ }
/* add AO in combined? */
if(R.wrld.mode & WO_AMB_OCC) {
@@ -1713,7 +1770,21 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
if(shi->combinedflag & SCE_PASS_SPEC)
VECADD(shr->combined, shr->combined, shr->spec);
+ /* 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];
+
+ QUATCOPY(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];
+ shr->alpha *= obcol[3];
+ }
+ }
+
shr->combined[3]= shr->alpha;
}
-
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
index 09a3b9ef66d..9bde6675798 100644
--- a/source/blender/render/intern/source/sss.c
+++ b/source/blender/render/intern/source/sss.c
@@ -59,6 +59,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_scene.h"
#include "BKE_utildefines.h"
/* this module */
@@ -450,13 +451,13 @@ static void compute_radiance(ScatterTree *tree, float *co, float *rad)
VECCOPY(rdsum, result.rdsum);
VECADD(backrdsum, result.rdsum, result.backrdsum);
- if(rdsum[0] > 0.0f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0];
- if(rdsum[1] > 0.0f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1];
- if(rdsum[2] > 0.0f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2];
+ 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] > 0.0f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0];
- if(backrdsum[1] > 0.0f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1];
- if(backrdsum[2] > 0.0f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[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]);
@@ -503,20 +504,20 @@ static void sum_leaf_radiance(ScatterTree *tree, ScatterNode *node)
}
}
- if(node->area > 0) {
+ if(node->area > 1e-16f) {
inv= 1.0/node->area;
node->rad[0] *= inv;
node->rad[1] *= inv;
node->rad[2] *= inv;
}
- if(node->backarea > 0) {
+ if(node->backarea > 1e-16f) {
inv= 1.0/node->backarea;
node->backrad[0] *= inv;
node->backrad[1] *= inv;
node->backrad[2] *= inv;
}
- if(totrad > 0.0f) {
+ if(totrad > 1e-16f) {
inv= 1.0/totrad;
node->co[0] *= inv;
node->co[1] *= inv;
@@ -577,20 +578,20 @@ static void sum_branch_radiance(ScatterTree *tree, ScatterNode *node)
node->backarea += subnode->backarea;
}
- if(node->area > 0) {
+ if(node->area > 1e-16f) {
inv= 1.0/node->area;
node->rad[0] *= inv;
node->rad[1] *= inv;
node->rad[2] *= inv;
}
- if(node->backarea > 0) {
+ if(node->backarea > 1e-16f) {
inv= 1.0/node->backarea;
node->backrad[0] *= inv;
node->backrad[1] *= inv;
node->backrad[2] *= inv;
}
- if(totrad > 0.0f) {
+ if(totrad > 1e-16f) {
inv= 1.0/totrad;
node->co[0] *= inv;
node->co[1] *= inv;
@@ -847,7 +848,7 @@ static void sss_create_tree_mat(Render *re, Material *mat)
{
SSSPoints *p;
RenderResult *rr;
- ListBase layers, points;
+ ListBase points;
float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL;
int totpoint = 0, osa, osaflag, partsdone;
@@ -860,13 +861,11 @@ static void sss_create_tree_mat(Render *re, Material *mat)
setting them back, maybe we need to create our own Render? */
/* do SSS preprocessing render */
- layers= re->r.layers;
+ rr= re->result;
osa= re->osa;
osaflag= re->r.mode & R_OSA;
partsdone= re->i.partsdone;
- rr= re->result;
- re->r.layers.first= re->r.layers.last= NULL;
re->osa= 0;
re->r.mode &= ~R_OSA;
re->sss_points= &points;
@@ -881,7 +880,6 @@ static void sss_create_tree_mat(Render *re, Material *mat)
re->i.partsdone= partsdone;
re->sss_mat= NULL;
re->sss_points= NULL;
- re->r.layers= layers;
re->osa= osa;
if (osaflag) re->r.mode |= R_OSA;
@@ -921,7 +919,8 @@ static void sss_create_tree_mat(Render *re, Material *mat)
float *col= mat->sss_col, *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_PREVIEWBUTS) && error < 0.5f)
error= 0.5f;
@@ -985,7 +984,7 @@ void make_sss_tree(Render *re)
re->stats_draw(&re->i);
for(mat= G.main->mat.first; mat; mat= mat->id.next)
- if(mat->id.us && (mat->sss_flag & MA_DIFF_SSS))
+ if(mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS))
sss_create_tree_mat(re, mat);
}
@@ -1024,8 +1023,8 @@ int sample_sss(Render *re, Material *mat, float *co, float *color)
return 0;
}
-int has_sss_tree(struct Render *re, struct Material *mat)
+int sss_pass_done(struct Render *re, struct Material *mat)
{
- return (re->sss_hash && BLI_ghash_lookup(re->sss_hash, 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
index 4f0e9764a43..05e36160f0e 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -35,12 +35,14 @@
#include "DNA_key_types.h"
#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_memarena.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_key.h"
#include "BKE_utildefines.h"
@@ -55,248 +57,9 @@
#include "zbuf.h"
/* to be removed */
-void merge_transp_passes(RenderLayer *rl, ShadeResult *shr);
-void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha);
void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco);
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, ObjectRen *obr, int zvlnr, float *ho1, float *ho2);
-int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag);
-void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, long *rdrect);
-void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf);
-
-/* *************** */
-
-#define BUCKETPRIMS_SIZE 256
-
-typedef struct BucketPrims {
- struct BucketPrims *next, *prev;
- void *prim[BUCKETPRIMS_SIZE];
- int totprim;
-} BucketPrims;
-
-typedef struct RenderBuckets {
- ListBase all;
- ListBase *inside;
- ListBase *overlap;
- int x, y;
- float insize[2];
- float zmulx, zmuly, zofsx, zofsy;
-} RenderBuckets;
-
-static void add_bucket_prim(ListBase *lb, void *prim)
-{
- BucketPrims *bpr= lb->last;
-
- if(!bpr || bpr->totprim == BUCKETPRIMS_SIZE) {
- bpr= MEM_callocN(sizeof(BucketPrims), "BucketPrims");
- BLI_addtail(lb, bpr);
- }
-
- bpr->prim[bpr->totprim++]= prim;
-}
-
-RenderBuckets *init_buckets(Render *re)
-{
- RenderBuckets *buckets;
- RenderPart *pa;
- float scalex, scaley, cropx, cropy;
- int x, y, tempparts= 0;
-
- buckets= MEM_callocN(sizeof(RenderBuckets), "RenderBuckets");
-
- if(!re->parts.first) {
- initparts(re);
- tempparts= 1;
- }
-
- pa= re->parts.first;
- if(!pa)
- return buckets;
-
- x= re->xparts+1;
- y= re->yparts+1;
- buckets->x= x;
- buckets->y= y;
-
- scalex= (2.0f - re->xparts*re->partx/(float)re->winx);
- scaley= (2.0f - re->yparts*re->party/(float)re->winy);
-
- cropx= pa->crop/(float)re->partx;
- cropy= pa->crop/(float)re->party;
-
- buckets->insize[0]= 1.0f - 2.0f*cropx;
- buckets->insize[1]= 1.0f - 2.0f*cropy;
-
- buckets->zmulx= re->xparts*scalex;
- buckets->zmuly= re->yparts*scaley;
- buckets->zofsx= scalex*(1.0f - cropx);
- buckets->zofsy= scaley*(1.0f - cropy);
-
- buckets->inside= MEM_callocN(sizeof(ListBase)*x*y, "BucketPrimsInside");
- buckets->overlap= MEM_callocN(sizeof(ListBase)*x*y, "BucketPrimsOverlap");
-
- if(tempparts)
- freeparts(re);
-
- return buckets;
-}
-
-void add_buckets_primitive(RenderBuckets *buckets, float *min, float *max, void *prim)
-{
- float end[3];
- int x, y, a;
-
- x= (int)min[0];
- y= (int)min[1];
-
- if(x >= 0 && x < buckets->x && y >= 0 && y < buckets->y) {
- a= y*buckets->x + x;
-
- end[0]= x + buckets->insize[0];
- end[1]= y + buckets->insize[1];
-
- if(max[0] <= end[0] && max[1] <= end[1]) {
- add_bucket_prim(&buckets->inside[a], prim);
- return;
- }
- else {
- end[0]= x + 2;
- end[1]= y + 2;
-
- if(max[0] <= end[0] && max[1] <= end[1]) {
- add_bucket_prim(&buckets->overlap[a], prim);
- return;
- }
- }
- }
-
- add_bucket_prim(&buckets->all, prim);
-}
-
-void free_buckets(RenderBuckets *buckets)
-{
- int a, size;
-
- BLI_freelistN(&buckets->all);
-
- size= buckets->x*buckets->y;
- for(a=0; a<size; a++) {
- BLI_freelistN(&buckets->inside[a]);
- BLI_freelistN(&buckets->overlap[a]);
- }
-
- if(buckets->inside)
- MEM_freeN(buckets->inside);
- if(buckets->overlap)
- MEM_freeN(buckets->overlap);
-
- MEM_freeN(buckets);
-}
-
-void project_hoco_to_bucket(RenderBuckets *buckets, float *hoco, float *bucketco)
-{
- float div;
-
- div= 1.0f/hoco[3];
- bucketco[0]= buckets->zmulx*(0.5 + 0.5f*hoco[0]*div) + buckets->zofsx;
- bucketco[1]= buckets->zmuly*(0.5 + 0.5f*hoco[1]*div) + buckets->zofsy;
-}
-
-typedef struct RenderPrimitiveIterator {
- Render *re;
- RenderBuckets *buckets;
- ListBase *list[6];
- int listindex, totlist;
- BucketPrims *bpr;
- int bprindex;
-
- ObjectInstanceRen *obi;
- StrandRen *strand;
- int index, tot;
-} RenderPrimitiveIterator;
-
-RenderPrimitiveIterator *init_primitive_iterator(Render *re, RenderBuckets *buckets, RenderPart *pa)
-{
- RenderPrimitiveIterator *iter;
- int nr, x, y, width;
-
- iter= MEM_callocN(sizeof(RenderPrimitiveIterator), "RenderPrimitiveIterator");
- iter->re= re;
-
- if(buckets) {
- iter->buckets= buckets;
-
- nr= BLI_findindex(&re->parts, pa);
- width= buckets->x - 1;
- x= (nr % width) + 1;
- y= (nr / width) + 1;
-
- iter->list[iter->totlist++]= &buckets->all;
- iter->list[iter->totlist++]= &buckets->inside[y*buckets->x + x];
- iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + x];
- iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + (x-1)];
- iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + (x-1)];
- iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + x];
- }
- else {
- iter->index= 0;
- iter->obi= re->instancetable.first;
- if(iter->obi)
- iter->tot= iter->obi->obr->totstrand;
- }
-
- return iter;
-}
-
-void *next_primitive_iterator(RenderPrimitiveIterator *iter)
-{
- if(iter->buckets) {
- if(iter->bpr && iter->bprindex >= iter->bpr->totprim) {
- iter->bpr= iter->bpr->next;
- iter->bprindex= 0;
- }
-
- while(iter->bpr == NULL) {
- if(iter->listindex == iter->totlist)
- return NULL;
-
- iter->bpr= iter->list[iter->listindex++]->first;
- iter->bprindex= 0;
- }
-
- return iter->bpr->prim[iter->bprindex++];
- }
- else {
- if(!iter->obi)
- return NULL;
-
- if(iter->index >= iter->tot) {
- while((iter->obi=iter->obi->next) && !iter->obi->obr->totstrand)
- iter->obi= iter->obi->next;
-
- if(iter->obi)
- iter->tot= iter->obi->obr->totstrand;
- else
- return NULL;
- }
-
- if(iter->index < iter->tot) {
- if((iter->index & 255)==0)
- iter->strand= iter->obi->obr->strandnodes[iter->index>>8].strand;
- else
- iter->strand++;
-
- return iter->strand;
- }
- else
- return NULL;
- }
-}
-
-void free_primitive_iterator(RenderPrimitiveIterator *iter)
-{
- MEM_freeN(iter);
-}
+void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, float *ho1, float *ho2);
/* *************** */
@@ -388,9 +151,9 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
Crossf(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];
- dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1];
- w= sqrt(dx*dx + dy*dy)/w;
+ dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
+ dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
+ w= sqrt(dx*dx + dy*dy);
if(w > 0.0f) {
if(strandbuf->flag & R_STRAND_B_UNITS) {
@@ -420,42 +183,9 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
/* *************** */
-typedef struct StrandPart {
- Render *re;
- ZSpan *zspan;
-
- RenderLayer *rl;
- ShadeResult *result;
- float *pass;
- int *rectz, *outrectz;
- unsigned short *mask;
- int rectx, recty;
- int addpassflag, addzbuf, sample;
-
- StrandSegment *segment;
- GHash *hash;
- StrandPoint point1, point2;
- ShadeSample ssamp1, ssamp2, ssamp;
- float t[3];
-} 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)
+static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v)
{
- 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;
+ v[0]= negt*v1[0] + t*v2[0];
}
static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
@@ -473,7 +203,7 @@ static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v
v[3]= negt*v1[3] + t*v2[3];
}
-static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
+void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
{
float negt= 1.0f - t;
@@ -484,6 +214,8 @@ static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float
}
/* 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) {
@@ -504,142 +236,336 @@ static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float
interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
if(addpassflag & SCE_PASS_RADIO)
interpolate_vec3(shr1->rad, shr2->rad, t, negt, shr->rad);
+ if(addpassflag & SCE_PASS_MIST)
+ interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist);
}
}
-static void add_strand_obindex(RenderLayer *rl, int offset, ObjectRen *obr)
+void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha)
{
- RenderPass *rpass;
-
- for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if(rpass->passtype == SCE_PASS_INDEXOB) {
- float *fp= rpass->rect + offset;
- *fp= (float)obr->ob->index;
- break;
- }
+ 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 do_strand_point_project(float winmat[][4], ZSpan *zspan, float *co, float *hoco, float *zco)
+void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint)
{
- projectvert(co, winmat, hoco);
- hoco_to_zco(zspan, zco, hoco);
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult *shr= ssamp->shr;
+ VlakRen vlr;
+
+ 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->strand= sseg->strand;
+ shi->obi= sseg->obi;
+ shi->obr= sseg->obi->obr;
+
+ /* cache for shadow */
+ shi->samplenr= re->shadowsamplenr[shi->thread]++;
+
+ shade_input_set_strand(shi, sseg->strand, spoint);
+ shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
+
+ /* init material vars */
+ // note, keep this synced with render_types.h
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ /* 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;
}
-static void strand_project_point(float winmat[][4], float winx, float winy, StrandPoint *spoint)
-{
- float div;
+/* *************** */
- projectvert(spoint->co, winmat, spoint->hoco);
+struct StrandShadeCache {
+ GHash *resulthash;
+ GHash *refcounthash;
+ MemArena *memarena;
+};
- div= 1.0f/spoint->hoco[3];
- spoint->x= spoint->hoco[0]*div*winx*0.5f;
- spoint->y= spoint->hoco[1]*div*winy*0.5f;
+StrandShadeCache *strand_shade_cache_create()
+{
+ StrandShadeCache *cache;
+
+ cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache");
+ cache->resulthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ cache->refcounthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+
+ return cache;
}
-#include "BLI_rand.h"
-static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint);
+void strand_shade_cache_free(StrandShadeCache *cache)
+{
+ BLI_ghash_free(cache->refcounthash, NULL, NULL);
+ BLI_ghash_free(cache->resulthash, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_memarena_free(cache->memarena);
+ MEM_freeN(cache);
+}
-static void strand_shade_get(StrandPart *spart, int lookup, ShadeSample *ssamp, StrandPoint *spoint, StrandVert *svert, StrandSegment *sseg)
+static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert)
{
ShadeResult *hashshr;
+ StrandPoint p;
+ int *refcount;
- if(lookup) {
- hashshr= BLI_ghash_lookup(spart->hash, svert);
+ hashshr= BLI_ghash_lookup(cache->resulthash, svert);
+ refcount= BLI_ghash_lookup(cache->refcounthash, svert);
- if(!hashshr) {
- strand_shade_point(spart->re, ssamp, sseg, spoint);
+ if(!hashshr) {
+ /* 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, &p);
- hashshr= MEM_callocN(sizeof(ShadeResult), "HashShadeResult");
- *hashshr= ssamp->shr[0];
- BLI_ghash_insert(spart->hash, svert, hashshr);
- }
- else {
- ssamp->shr[0]= *hashshr;
- BLI_ghash_remove(spart->hash, svert, NULL, (GHashValFreeFP)MEM_freeN);
- }
+ hashshr= MEM_callocN(sizeof(ShadeResult), "HashShadeResult");
+ *hashshr= ssamp->shr[0];
+ BLI_ghash_insert(cache->resulthash, svert, hashshr);
}
else
- strand_shade_point(spart->re, ssamp, sseg, spoint);
+ /* already shaded, just copy previous result from hash */
+ ssamp->shr[0]= *hashshr;
+
+ /* lower reference count and remove if not needed anymore by any samples */
+ (*refcount)--;
+ if(*refcount == 0) {
+ BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL);
+ }
}
-static void strand_shade_segment(StrandPart *spart)
+void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag)
{
- StrandSegment *sseg= spart->segment;
- int first, last;
+ ShadeResult shr1, shr2;
- if(!sseg->shaded) {
- first= (sseg->v[1] == &sseg->strand->vert[0]);
- last= (sseg->v[2] == &sseg->strand->vert[sseg->strand->totvert-1]);
+ /* 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];
- strand_shade_get(spart, !first, &spart->ssamp1, &sseg->point1, sseg->v[1], sseg);
- strand_shade_get(spart, !last, &spart->ssamp2, &sseg->point2, sseg->v[2], sseg);
- sseg->shaded= 1;
+ interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag);
+
+ /* apply alpha along width */
+ if(sseg->buffer->widthfade != 0.0f) {
+ s = 1.0f - pow(fabs(s), sseg->buffer->widthfade);
+
+ strand_apply_shaderesult_alpha(ssamp->shr, s);
}
+}
-#if 0
- float c[3];
-
- c[0]= BLI_frand();
- c[1]= BLI_frand();
- c[2]= BLI_frand();
+void strand_shade_unref(StrandShadeCache *cache, StrandVert *svert)
+{
+ int *refcount;
- spart->ssamp1.shr[0].combined[0] *= c[0];
- spart->ssamp1.shr[0].combined[1] *= c[1];
- spart->ssamp1.shr[0].combined[2] *= c[2];
+ /* lower reference count and remove if not needed anymore by any samples */
+ refcount= BLI_ghash_lookup(cache->refcounthash, svert);
- spart->ssamp2.shr[0].combined[0] *= c[0];
- spart->ssamp2.shr[0].combined[1] *= c[1];
- spart->ssamp2.shr[0].combined[2] *= c[2];
-#endif
+ (*refcount)--;
+ if(*refcount == 0) {
+ BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL);
+ }
}
-static void do_strand_blend(void *handle, int x, int y, float u, float v, float z)
+static void strand_shade_refcount(StrandShadeCache *cache, StrandVert *svert)
{
- StrandPart *spart= (StrandPart*)handle;
- StrandBuffer *buffer= spart->segment->buffer;
- ShadeResult *shr;
- float /**pass,*/ t;
- int offset, zverg;
+ int *refcount= BLI_ghash_lookup(cache->refcounthash, svert);
- /* check again solid z-buffer */
- offset = y*spart->rectx + x;
- zverg= (int)z;
+ if(!refcount) {
+ refcount= BLI_memarena_alloc(cache->memarena, sizeof(int));
+ *refcount= 1;
+ BLI_ghash_insert(cache->refcounthash, svert, refcount);
+ }
+ else
+ (*refcount)++;
+}
- if(zverg < spart->rectz[offset]) {
- /* fill in output z-buffer if needed */
- if(spart->addzbuf)
- if(zverg < spart->outrectz[offset])
- spart->outrectz[offset]= zverg;
+/* *************** */
- /* check alpha limit */
- shr= spart->result + offset*(spart->re->osa? spart->re->osa: 1);
- if(shr[spart->sample].combined[3]>0.999f)
- return;
+typedef struct StrandPart {
+ Render *re;
+ ZSpan *zspan;
- /* shade points if not shaded yet */
- strand_shade_segment(spart);
+ APixstrand *apixbuf;
+ int *totapixbuf;
+ int *rectz;
+ int *rectmask;
+ intptr_t *rectdaps;
+ int rectx, recty;
+ int sample;
- /* interpolate shading from two control points */
- t = u*spart->t[0] + v*spart->t[1] + (1.0f-u-v)*spart->t[2];
- interpolate_shade_result(spart->ssamp1.shr, spart->ssamp2.shr, t,
- spart->ssamp.shr, spart->addpassflag);
+ StrandSegment *segment;
+ float t[3], s[3];
- /* add in shaderesult array for part */
- spart->ssamp.shi[0].mask= (1<<spart->sample);
- addtosamp_shr(shr, &spart->ssamp, spart->addpassflag);
- spart->mask[offset] |= (1<<spart->sample);
+ StrandShadeCache *cache;
+} StrandPart;
-#if 0
- /* fill in pass for preview */
- if(spart->sample == 0) {
- pass= spart->pass + offset*4;
- QUATCOPY(pass, shr->combined);
+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], 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], 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;
+ }
+ }
}
-#endif
+ }
+ else {
+ bufferz= spart->rectz[offset];
+ 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; }
+#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; }
+
+ /* 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 = fabs(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(spart->addpassflag & SCE_PASS_INDEXOB)
- add_strand_obindex(spart->rl, offset, buffer->obr);
+ strand_shade_refcount(cache, sseg->v[1]);
+ strand_shade_refcount(cache, sseg->v[2]);
+ spart->totapixbuf[offset]++;
+ }
}
}
@@ -663,59 +589,6 @@ static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, floa
return clipflag;
}
-static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint)
-{
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
- VlakRen vlr;
-
- memset(&vlr, 0, sizeof(vlr));
- vlr.flag= R_SMOOTH;
- vlr.lay= sseg->strand->buffer->lay;
- vlr.obr= sseg->strand->buffer->obr;
- if(sseg->buffer->ma->mode & MA_TANGENT_STR)
- vlr.flag |= R_TANGENT;
-
- shi->vlr= &vlr;
- shi->obi= sseg->obi;
- shi->obr= sseg->obi->obr;
-
- /* cache for shadow */
- shi->samplenr++;
-
- shade_input_set_strand(shi, sseg->strand, spoint);
- shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
-
- /* init material vars */
- // note, keep this synced with render_types.h
- memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
- shi->har= shi->mat->har;
-
- /* shade */
- shade_samples_do_AO(ssamp);
- shade_input_do_shade(shi, shr);
-
- /* apply simplification */
- if(spoint->alpha < 1.0f) {
- shr->combined[0] *= spoint->alpha;
- shr->combined[1] *= spoint->alpha;
- shr->combined[2] *= spoint->alpha;
- shr->combined[3] *= spoint->alpha;
-
- shr->col[0] *= spoint->alpha;
- shr->col[1] *= spoint->alpha;
- shr->col[2] *= spoint->alpha;
- shr->col[3] *= spoint->alpha;
-
- shr->alpha *= 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]);
-}
-
static void do_scanconvert_strand(Render *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;
@@ -747,16 +620,22 @@ static void do_scanconvert_strand(Render *re, StrandPart *spart, ZSpan *zspan, f
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;
- zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_blend);
+ 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;
- zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_blend);
+ spart->s[2]= -1.0f;
+ zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac);
}
-static void strand_render(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, StrandPoint *p1, StrandPoint *p2)
+static void strand_render(Render *re, StrandSegment *sseg, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2)
{
if(spart) {
float t= p2->t;
@@ -771,18 +650,28 @@ static void strand_render(Render *re, float winmat[][4], StrandPart *spart, ZSpa
do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, 0);
}
else {
- float hoco1[4], hoco2[3];
-
- projectvert(p1->co, winmat, hoco1);
- projectvert(p2->co, winmat, hoco2);
-
- /* render both strand and single pixel wire to counter aliasing */
- zbufclip4(zspan, 0, 0, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, 0, 0, 0, 0);
- zbufsinglewire(zspan, 0, 0, hoco1, hoco2);
+ 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
+ similiar across frames, and so reduces flicker */
+ zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2);
+ }
}
}
-
-static int strand_segment_recursive(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
+
+static int strand_segment_recursive(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
{
StrandPoint p;
StrandBuffer *buffer= sseg->buffer;
@@ -815,19 +704,23 @@ static int strand_segment_recursive(Render *re, float winmat[][4], StrandPart *s
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, sseg, p1, &p, depth+1))
- strand_render(re, winmat, spart, zspan, p1, &p);
- if(!strand_segment_recursive(re, winmat, spart, zspan, sseg, &p, p2, depth+1))
- strand_render(re, winmat, spart, zspan, &p, p2);
+ 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], StrandPart *spart, ZSpan *zspan, StrandSegment *sseg)
+void render_strand_segment(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg)
{
StrandBuffer *buffer= sseg->buffer;
StrandPoint *p1= &sseg->point1;
@@ -848,149 +741,55 @@ void render_strand_segment(Render *re, float winmat[][4], StrandPart *spart, ZSp
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, sseg, p1, p2, 0))
- strand_render(re, winmat, spart, zspan, p1, p2);
-}
-
-static void zbuffer_strands_filter(Render *re, RenderPart *pa, RenderLayer *rl, StrandPart *spart, float *pass)
-{
- RenderResult *rr= pa->result;
- ShadeResult *shr, *shrrect= spart->result;
- float *passrect= pass;
- long *rdrect;
- int osa, x, y, a, crop= 0, offs=0, od;
-
- osa= (re->osa? re->osa: 1);
-
- /* filtered render, for now we assume only 1 filter size */
- if(pa->crop) {
- crop= 1;
- offs= pa->rectx + 1;
- passrect+= 4*offs;
- shrrect+= offs*osa;
- }
-
- rdrect= pa->rectdaps;
-
- /* zero alpha pixels get speed vector max again */
- if(spart->addpassflag & SCE_PASS_VECTOR)
- if(rl->layflag & SCE_LAY_SOLID)
- reset_sky_speedvectors(pa, rl, rl->scolrect);
-
- /* init scanline updates */
- rr->renrect.ymin= 0;
- rr->renrect.ymax= -pa->crop;
- rr->renlay= rl;
-
- /* filter the shade results */
- for(y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- pass= passrect;
- shr= shrrect;
- od= offs;
-
- for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, shr+=osa, pass+=4, od++) {
- if(spart->mask[od] == 0) {
- if(spart->addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, NULL, 0.0f, rdrect);
- }
- else {
- if(re->osa == 0) {
- addAlphaUnderFloat(pass, shr->combined);
- }
- else {
- for(a=0; a<re->osa; a++)
- add_filt_fmask(1<<a, shr[a].combined, pass, rr->rectx);
- }
-
- if(spart->addpassflag) {
- /* merge all in one, and then add */
- merge_transp_passes(rl, shr);
- add_transp_passes(rl, od, shr, pass[3]);
-
- if(spart->addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, shr->winspeed, pass[3], rdrect);
- }
- }
- }
-
- shrrect+= pa->rectx*osa;
- passrect+= 4*pa->rectx;
- offs+= pa->rectx;
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
+ 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 */
-unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *rl, float *pass)
+int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand *apixbuf, ListBase *apsmbase, StrandShadeCache *cache)
{
- //struct RenderPrimitiveIterator *iter;
ObjectRen *obr;
ObjectInstanceRen *obi;
ZSpan zspan;
StrandRen *strand=0;
StrandVert *svert;
+ StrandBound *sbound;
StrandPart spart;
StrandSegment sseg;
StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
MemArena *memarena;
float z[4], bounds[4], winmat[4][4];
- int a, b, i, resultsize, totsegment, clip[4];
+ int a, b, c, i, totsegment, clip[4];
if(re->test_break())
- return NULL;
+ return 0;
if(re->totstrand == 0)
- return NULL;
+ return 0;
/* setup StrandPart */
memset(&spart, 0, sizeof(spart));
spart.re= re;
- spart.rl= rl;
- spart.pass= pass;
spart.rectx= pa->rectx;
spart.recty= pa->recty;
+ spart.apixbuf= apixbuf;
+ spart.zspan= &zspan;
+ spart.rectdaps= pa->rectdaps;
spart.rectz= pa->rectz;
- spart.addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
- spart.addzbuf= rl->passflag & SCE_PASS_Z;
-
- if(re->osa) resultsize= pa->rectx*pa->recty*re->osa;
- else resultsize= pa->rectx*pa->recty;
- spart.result= MEM_callocN(sizeof(ShadeResult)*resultsize, "StrandPartResult");
- spart.mask= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "StrandPartMask");
-
- if(spart.addpassflag & SCE_PASS_VECTOR) {
- /* initialize speed vectors */
- for(a=0; a<resultsize; a++) {
- spart.result[a].winspeed[0]= PASS_VECTOR_MAX;
- spart.result[a].winspeed[1]= PASS_VECTOR_MAX;
- spart.result[a].winspeed[2]= PASS_VECTOR_MAX;
- spart.result[a].winspeed[3]= PASS_VECTOR_MAX;
- }
- }
-
- if(spart.addzbuf) {
- /* duplicate rectz so we can read from the old buffer, while
- * writing new z values */
- spart.rectz= MEM_dupallocN(pa->rectz);
- spart.outrectz= pa->rectz;
- }
-
- shade_sample_initialize(&spart.ssamp1, pa, rl);
- shade_sample_initialize(&spart.ssamp2, pa, rl);
- shade_sample_initialize(&spart.ssamp, pa, rl);
- spart.ssamp1.shi[0].sample= 0;
- spart.ssamp2.shi[0].sample= 1;
- spart.ssamp1.tot= 1;
- spart.ssamp2.tot= 1;
- spart.ssamp.tot= 1;
+ spart.rectmask= pa->rectmask;
+ spart.cache= cache;
zbuf_alloc_span(&zspan, pa->rectx, pa->recty, re->clipcrop);
@@ -1005,83 +804,83 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r
zspan.zofsx -= 0.5f;
zspan.zofsy -= 0.5f;
+ zspan.apsmbase= apsmbase;
+
/* clipping setup */
bounds[0]= (2*pa->disprect.xmin - re->winx-1)/(float)re->winx;
bounds[1]= (2*pa->disprect.xmax - re->winx+1)/(float)re->winx;
bounds[2]= (2*pa->disprect.ymin - re->winy-1)/(float)re->winy;
bounds[3]= (2*pa->disprect.ymax - re->winy+1)/(float)re->winy;
- /* sort segments */
- //iter= init_primitive_iterator(re, re->strandbuckets, pa);
-
memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
firstseg= NULL;
sortseg= sortsegments;
totsegment= 0;
- //while((strand = next_primitive_iterator(iter))) {
+ /* for all object instances */
for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
obr= obi->obr;
+ if(!obr->strandbuf || !(obr->strandbuf->lay & rl->lay))
+ continue;
+
+ /* compute matrix and try clipping whole object */
if(obi->flag & R_TRANSFORMED)
zbuf_make_winmat(re, obi->mat, winmat);
else
zbuf_make_winmat(re, NULL, winmat);
- for(a=0; a<obr->totstrand; a++) {
- if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
+ if(clip_render_object(obi->obr->boundbox, bounds, winmat))
+ continue;
- if(re->test_break())
- break;
-
-#if 0
- if(strand->clip)
+ /* 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, winmat))
continue;
-#endif
-
- svert= strand->vert;
-
- /* keep clipping and z depth for 4 control points */
- clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]);
- clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]);
- 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(winmat, &zspan, bounds, (svert+2)->co, &z[3]);
- }
- 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;
+ /* for each strand in this bounding box */
+ for(a=sbound->start; a<sbound->end; a++) {
+ strand= RE_findOrAddStrand(obr, a);
+ svert= strand->vert;
- sortseg->z= 0.5f*(z[1] + z[2]);
+ /* keep clipping and z depth for 4 control points */
+ clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]);
+ clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]);
+ clip[0]= clip[1]; z[0]= z[1];
- sortseg->next= firstseg;
- firstseg= sortseg;
- totsegment++;
+ 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(winmat, &zspan, bounds, (svert+2)->co, &z[3]);
+ }
+ 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];
}
-
- /* 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 0
- free_primitive_iterator(iter);
-#endif
-
if(!re->test_break()) {
/* convert list to array and sort */
sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
@@ -1092,7 +891,7 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r
BLI_memarena_free(memarena);
- spart.hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");
if(!re->test_break()) {
/* render segments in sorted order */
@@ -1120,135 +919,94 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r
spart.segment= &sseg;
- render_strand_segment(re, winmat, &spart, &zspan, &sseg);
+ render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
}
}
- // TODO printf(">>> %d\n", BLI_ghash_size(spart.hash));
- BLI_ghash_free(spart.hash, NULL, (GHashValFreeFP)MEM_freeN);
-
- zbuffer_strands_filter(re, pa, rl, &spart, pass);
-
- /* free */
- MEM_freeN(spart.result);
-
- if(spart.addzbuf)
- MEM_freeN(spart.rectz);
-
if(sortsegments)
MEM_freeN(sortsegments);
+ MEM_freeN(spart.totapixbuf);
zbuf_free_span(&zspan);
- if(!(re->osa && (rl->layflag & SCE_LAY_SOLID))) {
- MEM_freeN(spart.mask);
- spart.mask= NULL;
- }
-
- return spart.mask;
+ return totsegment;
}
-void project_strands(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int do_buckets)
-{
-#if 0
- ObjectRen *obr;
- StrandRen *strand = NULL;
- StrandVert *svert;
- float hoco[4], min[2], max[2], bucketco[2], vec[3];
- int a, b;
- /* float bmin[3], bmax[3], bpad[3], padding[2]; */
-
- if(re->strandbuckets) {
- free_buckets(re->strandbuckets);
- re->strandbuckets= NULL;
- }
-
- if(re->totstrand == 0)
- return;
-
- if(do_buckets)
- re->strandbuckets= init_buckets(re);
+/* *************** */
- /* calculate view coordinates (and zbuffer value) */
- for(obr=re->objecttable.first; obr; obr=obr->next) {
- for(a=0; a<obr->totstrand; a++) {
- if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
+StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[][4], int timeoffset)
+{
+ StrandSurface *mesh;
+ MFace *mface;
+ MVert *mvert;
+ float (*co)[3];
+ int a, totvert, totface;
+
+ totvert= dm->getNumVerts(dm);
+ totface= dm->getNumFaces(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;
- strand->clip= ~0;
+ 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->col= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCol");
+ 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;
-#if 0
- if(!(strand->buffer->flag & R_STRAND_BSPLINE)) {
- INIT_MINMAX(bmin, bmax);
- svert= strand->vert;
- for(b=0; b<strand->totvert; b++, svert++)
- DO_MINMAX(svert->co, bmin, bmax)
+ mvert= dm->getVertArray(dm);
+ for(a=0; a<mesh->totvert; a++, mvert++) {
+ VECCOPY(co[a], mvert->co);
+ Mat4MulVecfl(mat, co[a]);
+ }
- bpad[0]= (bmax[0]-bmin[0])*0.2f;
- bpad[1]= (bmax[1]-bmin[1])*0.2f;
- bpad[2]= (bmax[2]-bmin[2])*0.2f;
- }
- else
- bpad[0]= bpad[1]= bpad[2]= 0.0f;
-
- ma= strand->buffer->ma;
- width= MAX2(ma->strand_sta, ma->strand_end);
- if(strand->buffer->flag & R_STRAND_B_UNITS) {
- bpad[0] += 0.5f*width;
- bpad[1] += 0.5f*width;
- bpad[2] += 0.5f*width;
- }
-#endif
+ mface= dm->getFaceArray(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;
+ }
- INIT_MINMAX2(min, max);
- svert= strand->vert;
- for(b=0; b<strand->totvert; b++, svert++) {
- //VECADD(vec, svert->co, bpad);
+ return mesh;
+}
- /* same as VertRen */
- if(do_pano) {
- vec[0]= re->panoco*svert->co[0] + re->panosi*svert->co[2];
- vec[1]= svert->co[1];
- vec[2]= -re->panosi*svert->co[0] + re->panoco*svert->co[2];
- }
- else
- VECCOPY(vec, svert->co)
+void free_strand_surface(Render *re)
+{
+ StrandSurface *mesh;
- /* Go from wcs to hcs ... */
- projectfunc(vec, re->winmat, hoco);
- /* ... and clip in that system. */
- strand->clip &= testclip(hoco);
+ 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->col) MEM_freeN(mesh->col);
+ if(mesh->face) MEM_freeN(mesh->face);
+ }
-#if 0
- if(do_buckets) {
- project_hoco_to_bucket(re->strandbuckets, hoco, bucketco);
- DO_MINMAX2(bucketco, min, max);
- }
-#endif
- }
+ BLI_freelistN(&re->strandsurface);
+}
-#if 0
- if(do_buckets) {
- if(strand->buffer->flag & R_STRAND_BSPLINE) {
- min[0] -= width;
- min[1] -= width;
- max[0] += width;
- max[1] += width;
- }
- else {
- /* catmull-rom stays within 1.2f bounds in object space,
- * is this still true after projection? */
- min[0] -= width + (max[0]-min[0])*0.2f;
- min[1] -= width + (max[1]-min[1])*0.2f;
- max[0] += width + (max[0]-min[0])*0.2f;
- max[1] += width + (max[1]-min[1])*0.2f;
- }
+void strand_minmax(StrandRen *strand, float *min, float *max)
+{
+ StrandVert *svert;
+ int a;
- add_buckets_primitive(re->strandbuckets, min, max, strand);
- }
-#endif
- }
- }
-#endif
+ for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++)
+ DO_MINMAX(svert->co, min, max)
}
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
new file mode 100644
index 00000000000..2b490e71142
--- /dev/null
+++ b/source/blender/render/intern/source/sunsky.c
@@ -0,0 +1,499 @@
+ /**
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include "sunsky.h"
+#include "math.h"
+#include "BLI_arithb.h"
+#include "BKE_global.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]);
+
+/**
+ * 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));
+
+/**
+ * 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]);
+
+/**
+ * ClipColor:
+ * clip a color to range [0,1];
+ * */
+void ClipColor(float c[3])
+{
+ if (c[0] > 1.0) c[0] = 1.0;
+ if (c[0] < 0.0) c[0] = 0.0;
+ if (c[1] > 1.0) c[1] = 1.0;
+ if (c[1] < 0.0) c[1] = 0.0;
+ if (c[2] > 1.0) c[2] = 1.0;
+ if (c[2] < 0.0) c[2] = 0.0;
+}
+
+/**
+ * AngleBetween:
+ * compute angle between to direction
+ * all angles are in radians
+ * */
+static float AngleBetween(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta);
+
+ if (cospsi > 1.0)
+ return 0;
+ if (cospsi < -1.0)
+ return M_PI;
+
+ return acos(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 = acos(toSun[2]);
+ if (fabs(*theta) < 1e-5)
+ *phi = 0;
+ else
+ *phi = atan2(toSun[1], toSun[0]);
+}
+
+/**
+ * PerezFunction:
+ * compute perez function value based on input paramters
+ * */
+float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz)
+{
+ float den, num;
+
+ den = ((1 + lam[0] * exp(lam[1])) *
+ (1 + lam[2] * exp(lam[3] * sunsky->theta) + lam[4] * cos(sunsky->theta) * cos(sunsky->theta)));
+
+ num = ((1 + lam[0] * exp(lam[1] / cos(theta))) *
+ (1 + lam[2] * exp(lam[3] * gamma) + lam[4] * cos(gamma) * cos(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 informtion 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, float *toSun, 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.0 / 9.0 - T / 120.0) * (M_PI - 2 * sunsky->theta);
+ sunsky->zenith_Y = (4.0453 * T - 4.9710) * tan(chi) - .2155 * T + 2.4192;
+ 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.00165 * theta3 - 0.00374 * theta2 + 0.00208 * sunsky->theta + 0) * T2 +
+ ( -0.02902 * theta3 + 0.06377 * theta2 - 0.03202 * sunsky->theta + 0.00394) * T +
+ ( + 0.11693 * theta3 - 0.21196 * theta2 + 0.06052 * sunsky->theta + 0.25885);
+
+ sunsky->zenith_y =
+ ( + 0.00275 * theta3 - 0.00610 * theta2 + 0.00316 * sunsky->theta + 0) * T2 +
+ ( -0.04214 * theta3 + 0.08970 * theta2 - 0.04153 * sunsky->theta + 0.00515) * T +
+ ( + 0.15346 * theta3 - 0.26756 * theta2 + 0.06669 * sunsky->theta + 0.26688);
+
+
+ sunsky->perez_Y[0] = 0.17872 * T - 1.46303;
+ sunsky->perez_Y[1] = -0.35540 * T + 0.42749;
+ sunsky->perez_Y[2] = -0.02266 * T + 5.32505;
+ sunsky->perez_Y[3] = 0.12064 * T - 2.57705;
+ sunsky->perez_Y[4] = -0.06696 * T + 0.37027;
+
+ sunsky->perez_x[0] = -0.01925 * T - 0.25922;
+ sunsky->perez_x[1] = -0.06651 * T + 0.00081;
+ sunsky->perez_x[2] = -0.00041 * T + 0.21247;
+ sunsky->perez_x[3] = -0.06409 * T - 0.89887;
+ sunsky->perez_x[4] = -0.00325 * T + 0.04517;
+
+ sunsky->perez_y[0] = -0.01669 * T - 0.26078;
+ sunsky->perez_y[1] = -0.09495 * T + 0.00921;
+ sunsky->perez_y[2] = -0.00792 * T + 0.21023;
+ sunsky->perez_y[3] = -0.04405 * T - 1.65369;
+ sunsky->perez_y[4] = -0.01092 * T + 0.05291;
+
+ /* suggested by glome in
+ * http://projects.blender.org/tracker/?func=detail&atid=127&aid=8063&group_id=9*/
+ 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>(0.5*M_PI)) {
+ hfade = 1.0-(theta*M_1_PI-0.5)*2.0;
+ hfade = hfade*hfade*(3.0-2.0*hfade);
+ theta = 0.5*M_PI;
+ }
+
+ if (sunsky->theta>(0.5*M_PI)) {
+ if (theta<=0.5*M_PI) {
+ nfade = 1.0-(0.5-theta*M_1_PI)*2.0;
+ nfade *= 1.0-(sunsky->theta*M_1_PI-0.5)*2.0;
+ nfade = nfade*nfade*(3.0-2.0*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-5 * 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];
+
+ VecCopyf(v, (float*)varg);
+ Normalize(v);
+
+ if (v[2] < 0.001){
+ v[2] = 0.001;
+ Normalize(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
+ * */
+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.0/(cos(theta) + 0.15f*pow(93.885f-theta/M_PI*180.0f,-1.253f));
+
+ for(i = 0; i < 3; i++)
+ {
+ // Rayleigh Scattering
+ fTauR = exp( -m * 0.008735f * pow(fLambda[i], (float)(-4.08f)));
+
+ // Aerosal (water + dust) attenuation
+ fTauA = exp(-m * fBeta * pow(fLambda[i], -fAlpha));
+
+ fTau[i] = fTauR * fTauA;
+ }
+}
+
+/**
+ * InitAtmosphere:
+ * this function intiate 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, multiplyed 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 = 3.14159265358f;
+ 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.544*T - 6.51)*1e-17;
+ 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.434*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 = Inpf(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/log(2));
+ E1[0] = exp(E1[0]);
+ E1[1] = exp(E1[1]);
+ E1[2] = exp(E1[2]);
+
+ VecCopyf(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 * sqrt(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.0, -, E1);
+ vec3opv(vTemp1, vTemp1, *, vTemp2);
+
+ fopvec3(vTemp2, 1.0, / , 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.c b/source/blender/render/intern/source/texture.c
index b502fb2b421..7ce66ff6d12 100644
--- a/source/blender/render/intern/source/texture.c
+++ b/source/blender/render/intern/source/texture.c
@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_library.h"
#include "BKE_image.h"
@@ -98,7 +99,7 @@ void init_render_texture(Render *re, Tex *tex)
}
else if(tex->type==TEX_ENVMAP) {
/* just in case */
- tex->imaflag= TEX_INTERPOL | TEX_MIPMAP;
+ tex->imaflag |= TEX_INTERPOL | TEX_MIPMAP;
tex->extend= TEX_CLIP;
if(tex->env) {
@@ -720,30 +721,59 @@ static int plugintex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex
{
PluginTex *pit;
int rgbnor=0;
+ float result[ 8 ];
texres->tin= 0.0;
pit= tex->plugin;
if(pit && pit->doit) {
if(texres->nor) {
- VECCOPY(pit->result+5, texres->nor);
+ if (pit->version < 6) {
+ VECCOPY(pit->result+5, texres->nor);
+ } else {
+ VECCOPY(result+5, texres->nor);
+ }
+ }
+ if (pit->version < 6) {
+ if(osatex) rgbnor= ((TexDoitold)pit->doit)(tex->stype,
+ pit->data, texvec, dxt, dyt);
+ else rgbnor= ((TexDoitold)pit->doit)(tex->stype,
+ pit->data, texvec, 0, 0);
+ } else {
+ if(osatex) rgbnor= ((TexDoit)pit->doit)(tex->stype,
+ pit->data, texvec, dxt, dyt, result);
+ else rgbnor= ((TexDoit)pit->doit)(tex->stype,
+ pit->data, texvec, 0, 0, result);
}
- if(osatex) rgbnor= ((TexDoit)pit->doit)(tex->stype, pit->data, texvec, dxt, dyt);
- else rgbnor= ((TexDoit)pit->doit)(tex->stype, pit->data, texvec, 0, 0);
- texres->tin= pit->result[0];
+ if (pit->version < 6) {
+ texres->tin = pit->result[0];
+ } else {
+ texres->tin = result[0];
+ }
if(rgbnor & TEX_NOR) {
if(texres->nor) {
- VECCOPY(texres->nor, pit->result+5);
+ if (pit->version < 6) {
+ VECCOPY(texres->nor, pit->result+5);
+ } else {
+ VECCOPY(texres->nor, result+5);
+ }
}
}
if(rgbnor & TEX_RGB) {
- texres->tr= pit->result[1];
- texres->tg= pit->result[2];
- texres->tb= pit->result[3];
- texres->ta= pit->result[4];
+ if (pit->version < 6) {
+ texres->tr = pit->result[1];
+ texres->tg = pit->result[2];
+ texres->tb = pit->result[3];
+ texres->ta = pit->result[4];
+ } else {
+ texres->tr = result[1];
+ texres->tg = result[2];
+ texres->tb = result[3];
+ texres->ta = result[4];
+ }
BRICONTRGB;
}
@@ -1202,6 +1232,8 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
return retval;
}
+/* 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 */
int multitex_ext(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
@@ -1255,7 +1287,7 @@ void texture_rgb_blend(float *in, float *tex, float *out, float fact, float facg
in[1]= (fact*tex[1] + facm*out[1]);
in[2]= (fact*tex[2] + facm*out[2]);
break;
-
+
case MTEX_MUL:
fact*= facg;
facm= 1.0-facg;
@@ -1343,9 +1375,28 @@ void texture_rgb_blend(float *in, float *tex, float *out, float fact, float facg
col= fact*tex[2];
if(col > out[2]) in[2]= col; else in[2]= out[2];
break;
+
+ case MTEX_BLEND_HUE:
+ fact*= facg;
+ VECCOPY(in, out);
+ ramp_blend(MA_RAMP_HUE, in, in+1, in+2, fact, tex);
+ break;
+ case MTEX_BLEND_SAT:
+ fact*= facg;
+ VECCOPY(in, out);
+ ramp_blend(MA_RAMP_SAT, in, in+1, in+2, fact, tex);
+ break;
+ case MTEX_BLEND_VAL:
+ fact*= facg;
+ VECCOPY(in, out);
+ ramp_blend(MA_RAMP_VAL, in, in+1, in+2, fact, tex);
+ break;
+ case MTEX_BLEND_COLOR:
+ fact*= facg;
+ VECCOPY(in, out);
+ ramp_blend(MA_RAMP_COLOR, in, in+1, in+2, fact, tex);
+ break;
}
-
-
}
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype, int flip)
@@ -1427,7 +1478,14 @@ void do_material_tex(ShadeInput *shi)
/* which coords */
if(mtex->texco==TEXCO_ORCO) {
- co= shi->lo; dx= shi->dxlo; dy= shi->dylo;
+ 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_STICKY) {
co= shi->sticky; dx= shi->dxsticky; dy= shi->dysticky;
@@ -1439,6 +1497,9 @@ void do_material_tex(ShadeInput *shi)
dx= dxt;
dy= dyt;
VECCOPY(tempvec, shi->co);
+ if(mtex->texflag & MTEX_OB_DUPLI_ORIG)
+ if(shi->obi && shi->obi->duplitexmat)
+ MTC_Mat4MulVecfl(shi->obi->duplitexmat, tempvec);
MTC_Mat4MulVecfl(ob->imat, tempvec);
if(shi->osatex) {
VECCOPY(dxt, shi->dxco);
@@ -1466,28 +1527,35 @@ void do_material_tex(ShadeInput *shi)
co= shi->gl; dx= shi->dxco; dy= shi->dyco;
}
else if(mtex->texco==TEXCO_UV) {
- ShadeInputUV *suv= &shi->uv[shi->actuv];
- int i;
-
- if(mtex->uvname[0] != 0) {
- for(i = 0; i < shi->totuv; i++) {
- if(strcmp(shi->uv[i].name, mtex->uvname)==0) {
- suv= &shi->uv[i];
- break;
+ 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;
+
+ if(mtex->uvname[0] != 0) {
+ for(i = 0; i < shi->totuv; i++) {
+ if(strcmp(shi->uv[i].name, mtex->uvname)==0) {
+ suv= &shi->uv[i];
+ break;
+ }
}
}
- }
- co= suv->uv;
- dx= suv->dxuv;
- dy= suv->dyuv;
+ co= suv->uv;
+ dx= suv->dxuv;
+ dy= suv->dyuv;
+ }
}
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->strand;
+ co[0]= shi->strandco;
co[1]= co[2]= 0.0f;
dx[0]= shi->dxstrand;
dx[1]= dx[2]= 0.0f;
@@ -1644,18 +1712,18 @@ void do_material_tex(ShadeInput *shi)
texres.nor[2]= texres.tb;
}
else {
- float co= 0.5*cos(texres.tin-0.5);
+ float co_nor= 0.5*cos(texres.tin-0.5);
float si= 0.5*sin(texres.tin-0.5);
float f1, f2;
f1= shi->vn[0];
f2= shi->vn[1];
- texres.nor[0]= f1*co+f2*si;
- texres.nor[1]= f2*co-f1*si;
+ texres.nor[0]= f1*co_nor+f2*si;
+ texres.nor[1]= f2*co_nor-f1*si;
f1= shi->vn[1];
f2= shi->vn[2];
- texres.nor[1]= f1*co+f2*si;
- texres.nor[2]= f2*co-f1*si;
+ texres.nor[1]= f1*co_nor+f2*si;
+ texres.nor[2]= f2*co_nor-f1*si;
}
}
// warping, local space
@@ -1743,11 +1811,11 @@ void do_material_tex(ShadeInput *shi)
if(mtex->normapspace == MTEX_NSPACE_TANGENT) {
/* qdn: tangent space */
float B[3], tv[3];
- Crossf(B, shi->vn, shi->tang); /* bitangent */
+ Crossf(B, shi->vn, shi->nmaptang); /* bitangent */
/* transform norvec from tangent space to object surface in camera space */
- tv[0] = texres.nor[0]*shi->tang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0];
- tv[1] = texres.nor[0]*shi->tang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1];
- tv[2] = texres.nor[0]*shi->tang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2];
+ tv[0] = texres.nor[0]*shi->nmaptang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0];
+ tv[1] = texres.nor[0]*shi->nmaptang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1];
+ tv[2] = texres.nor[0]*shi->nmaptang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2];
shi->vn[0]= facm*shi->vn[0] + fact*tv[0];
shi->vn[1]= facm*shi->vn[1] + fact*tv[1];
shi->vn[2]= facm*shi->vn[2] + fact*tv[2];
@@ -1762,8 +1830,8 @@ void do_material_tex(ShadeInput *shi)
Mat4Mul3Vecfl(R.viewmat, nor);
}
else if(mtex->normapspace == MTEX_NSPACE_OBJECT) {
- if(shi->vlr && shi->vlr->obr->ob)
- Mat4Mul3Vecfl(shi->vlr->obr->ob->obmat, nor);
+ if(shi->obr && shi->obr->ob)
+ Mat4Mul3Vecfl(shi->obr->ob->obmat, nor);
Mat4Mul3Vecfl(R.viewmat, nor);
}
@@ -1776,24 +1844,24 @@ void do_material_tex(ShadeInput *shi)
}
}
else {
+ float nor[3], dot;
+
if(shi->mat->mode & MA_TANGENT_V) {
shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
}
- else {
- float nor[3], dot;
- /* prevent bump to become negative normal */
- nor[0]= Tnor*tex->norfac*texres.nor[0];
- nor[1]= Tnor*tex->norfac*texres.nor[1];
- nor[2]= Tnor*tex->norfac*texres.nor[2];
-
- dot= 0.5f + 0.5f*INPR(nor, shi->vn);
-
- shi->vn[0]+= dot*nor[0];
- shi->vn[1]+= dot*nor[1];
- shi->vn[2]+= dot*nor[2];
- }
+
+ /* prevent bump to become negative normal */
+ nor[0]= Tnor*tex->norfac*texres.nor[0];
+ nor[1]= Tnor*tex->norfac*texres.nor[1];
+ nor[2]= Tnor*tex->norfac*texres.nor[2];
+
+ dot= 0.5f + 0.5f*INPR(nor, shi->vn);
+
+ shi->vn[0]+= dot*nor[0];
+ shi->vn[1]+= dot*nor[1];
+ shi->vn[2]+= dot*nor[2];
}
Normalize(shi->vn);
@@ -2233,7 +2301,7 @@ void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, f
/* ------------------------------------------------------------------------- */
/* colf supposed to be initialized with la->r,g,b */
-void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf)
+void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf, int effect)
{
Object *ob;
MTex *mtex;
@@ -2372,7 +2440,7 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf)
}
/* mapping */
- if(mtex->mapto & LAMAP_COL) {
+ if(((mtex->mapto & LAMAP_COL) && (effect & LA_TEXTURE))||((mtex->mapto & LAMAP_SHAD) && (effect & LA_SHAD_TEX))) {
float col[3];
if(rgb==0) {
@@ -2450,21 +2518,31 @@ int externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *t
void render_realtime_texture(ShadeInput *shi, Image *ima)
{
TexResult texr;
- static Tex tex1, tex2; // threadsafe
+ 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) {
- firsttime= 0;
- default_tex(&tex1);
- default_tex(&tex2);
- tex1.type= TEX_IMAGE;
- tex2.type= TEX_IMAGE;
+ BLI_lock_thread(LOCK_IMAGE);
+ if(firsttime) {
+ for(a=0; a<BLENDER_MAX_THREADS; a++) {
+ memset(&imatex[a], 0, sizeof(Tex));
+ default_tex(&imatex[a]);
+ imatex[a].type= TEX_IMAGE;
+ }
+
+ firsttime= 0;
+ }
+ BLI_unlock_thread(LOCK_IMAGE);
}
- if(shi->ys & 1) tex= &tex1; else tex= &tex2; // threadsafe
+ tex= &imatex[shi->thread];
+ tex->iuser.ok= ima->ok;
texvec[0]= 0.5+0.5*suv->uv[0];
texvec[1]= 0.5+0.5*suv->uv[1];
@@ -2480,7 +2558,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr);
else imagewrap(tex, ima, NULL, texvec, &texr);
-
+
shi->vcol[0]*= texr.tr;
shi->vcol[1]*= texr.tg;
shi->vcol[2]*= texr.tb;
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 57d2bbb3489..509ac81c58b 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -196,7 +196,6 @@ static void zbuf_add_to_span(ZSpan *zspan, float *v1, float *v2)
/* Functions */
/*-----------------------------------------------------------*/
-
void fillrect(int *rect, int x, int y, int val)
{
int len, *drect;
@@ -307,8 +306,8 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
float x0,y0,z0;
float x1,y1,z1,x2,y2,z2,xx1;
float *span1, *span2;
- int *rz, x, y;
- int sn1, sn2, rectx, *rectzofs, my0, my2, mask;
+ int *rz, *rm, x, y;
+ int sn1, sn2, rectx, *rectzofs, *rectmaskofs, my0, my2, mask;
/* init */
zbuf_init_span(zspan);
@@ -353,6 +352,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
/* 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;
@@ -377,35 +377,40 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
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) {
- if( (int)zverg < *rz) {
-// int i= zvlnr & 3;
-
- apn= ap;
- while(apn) {
- if(apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= zverg; 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]= zverg; 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]= zverg; 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]= zverg; apn->mask[3]= mask; break; }
- if(apn->p[3]==zvlnr && apn->obi[3]==obi) {apn->mask[3]|= mask; break; }
-// if(apn->p[i]==0) {apn->obi[i]= obi; apn->p[i]= zvlnr; apn->z[i]= zverg; apn->mask[i]= mask; break; }
-// if(apn->p[i]==zvlnr && apn->obi[i]==obi) {apn->mask[i]|= mask; break; }
- if(apn->next==NULL) apn->next= addpsA(zspan);
- apn= apn->next;
- }
+ intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+
+ 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--;
}
@@ -413,6 +418,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
zy0-=zyd;
rectzofs-= rectx;
+ rectmaskofs-= rectx;
apofs-= rectx;
}
}
@@ -422,7 +428,7 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
{
APixstr *ap, *apn;
- int *rectz;
+ int *rectz, *rectmask;
int start, end, x, y, oldx, oldy, ofs;
int dz, vergz, mask, maxtest=0;
float dx, dy;
@@ -459,37 +465,40 @@ static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec
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++, ap++) {
+ 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) {
-
- 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==0) apn->next= addpsA(zspan);
- apn= apn->next;
- }
+ 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==0) apn->next= addpsA(zspan);
+ apn= apn->next;
+ }
+ }
}
}
@@ -527,37 +536,40 @@ static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec
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, ap+=zspan->rectx) {
+ 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) {
-
- apn= ap;
- while(apn) { /* loop unrolled */
- if(apn->p[0]==0) {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->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->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->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==0) apn->next= addpsA(zspan);
- apn= apn->next;
- }
-
+ 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==0) apn->next= addpsA(zspan);
+ apn= apn->next;
+ }
+ }
}
}
@@ -572,7 +584,7 @@ static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec
static void zbufline(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
{
- int *rectz, *rectp, *recto;
+ int *rectz, *rectp, *recto, *rectmask;
int start, end, x, y, oldx, oldy, ofs;
int dz, vergz, maxtest= 0;
float dx, dy;
@@ -608,11 +620,12 @@ static void zbufline(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
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++) {
+ for(x= start; x<=end; x++, rectz++, rectp++, recto++, rectmask++) {
y= floor(v1[1]);
if(y!=oldy) {
@@ -620,13 +633,16 @@ static void zbufline(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
rectz+= ofs;
rectp+= ofs;
recto+= ofs;
+ rectmask+= ofs;
}
if(x>=0 && y>=0 && y<zspan->recty) {
if(vergz<*rectz) {
- *recto= obi;
- *rectz= vergz;
- *rectp= zvlnr;
+ if(!zspan->rectmask || vergz>*rectmask) {
+ *recto= obi;
+ *rectz= vergz;
+ *rectp= zvlnr;
+ }
}
}
@@ -663,11 +679,12 @@ static void zbufline(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
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) {
+ 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) {
@@ -675,13 +692,16 @@ static void zbufline(ZSpan *zspan, int obi, int zvlnr, float *vec1, float *vec2)
rectz+= ofs;
rectp+= ofs;
recto+= ofs;
+ rectmask+= ofs;
}
if(x>=0 && y>=0 && x<zspan->rectx) {
if(vergz<*rectz) {
- *rectz= vergz;
- *rectp= zvlnr;
- *recto= obi;
+ if(!zspan->rectmask || vergz>*rectmask) {
+ *rectz= vergz;
+ *rectp= zvlnr;
+ *recto= obi;
+ }
}
}
@@ -1022,6 +1042,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v
float *span1, *span2;
int *rectoofs, *ro;
int *rectpofs, *rp;
+ int *rectmaskofs, *rm;
int *rz, x, y;
int sn1, sn2, rectx, *rectzofs, my0, my2;
@@ -1072,6 +1093,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v
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;
@@ -1094,22 +1116,30 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v
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) {
- if( (int)zverg > *rz || *rz==0x7FFFFFFF) {
- *ro= obi;
- *rz= (int)zverg;
- *rp= zvlnr;
+ intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+
+ if( intzverg > *rz || *rz==0x7FFFFFFF) {
+ if(!zspan->rectmask || intzverg > *rm) {
+ *ro= obi;
+ *rz= intzverg;
+ *rp= zvlnr;
+ }
}
zverg+= zxd;
rz++;
rp++;
ro++;
+ rm++;
x--;
}
}
@@ -1118,6 +1148,7 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v
rectzofs-= rectx;
rectpofs-= rectx;
rectoofs-= rectx;
+ rectmaskofs-= rectx;
}
}
@@ -1131,6 +1162,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
float *span1, *span2;
int *rectoofs, *ro;
int *rectpofs, *rp;
+ int *rectmaskofs, *rm;
int *rz, x, y;
int sn1, sn2, rectx, *rectzofs, my0, my2;
@@ -1181,6 +1213,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
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;
@@ -1203,22 +1236,30 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
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) {
- if( (int)zverg < *rz) {
- *rz= (int)zverg;
- *rp= zvlnr;
- *ro= obi;
+ intzverg= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+
+ if(intzverg < *rz) {
+ if(!zspan->rectmask || intzverg > *rm) {
+ *rz= intzverg;
+ *rp= zvlnr;
+ *ro= obi;
+ }
}
zverg+= zxd;
rz++;
rp++;
ro++;
+ rm++;
x--;
}
}
@@ -1227,6 +1268,7 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, float *v1, float *v2,
rectzofs-= rectx;
rectpofs-= rectx;
rectoofs-= rectx;
+ rectmaskofs-= rectx;
}
}
@@ -1326,7 +1368,8 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int obi, int zvlnr, float *v1, float
x= sn2-sn1;
while(x>=0) {
- int zvergi= (int)zverg;
+ int zvergi= (int)CLAMPIS(zverg, INT_MIN, INT_MAX);
+
/* option: maintain two depth values, closest and 2nd closest */
if(zvergi < *rz) {
if(rectzofs1) *rz1= *rz;
@@ -1922,10 +1965,82 @@ void zbufclip4(ZSpan *zspan, int obi, int zvlnr, float *f1, float *f2, float *f3
zspan->zbuffunc(zspan, obi, zvlnr, vez, vez+4, vez+8, vez+12);
}
+/* ************** ZMASK ******************************** */
+
+#define EXTEND_PIXEL(a) if(temprectp[a]) {z+= rectz[a]; tot++;}
+
+/* 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, unsigned int lay, short layflag, void(*fillfunc)(RenderPart*, ZSpan*, int, void*), void *data)
+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 */
@@ -1935,9 +2050,12 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag, void(*fillfu
ObjectInstanceRen *obi;
ObjectRen *obr;
float winmat[4][4], bounds[4], ho1[4], ho2[4], ho3[4], ho4[4]={0};
+ unsigned int lay= rl->lay, lay_zmask= rl->lay_zmask;
int i, v, zvlnr, zsample, samples, c1, c2, c3, c4=0;
- short nofill=0, env=0, wire=0, all_z= layflag & SCE_LAY_ALL_Z;
-
+ short nofill=0, env=0, wire=0, zmaskpass=0;
+ short all_z= (rl->layflag & SCE_LAY_ALL_Z) && !(rl->layflag & SCE_LAY_ZMASK);
+ short neg_zmask= (rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK);
+
samples= (R.osa? R.osa: 1);
samples= MIN2(4, samples-pa->sample);
@@ -1969,9 +2087,13 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag, void(*fillfu
/* the buffers */
if(zsample == samples-1) {
- zspan->rectz= pa->rectz;
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");
@@ -1982,104 +2104,153 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag, void(*fillfu
fillrect(zspan->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
fillrect(zspan->rectp, pa->rectx, pa->recty, 0);
fillrect(zspan->recto, pa->rectx, pa->recty, 0);
-
- /* filling methods */
- zspan->zbuffunc= zbuffillGL4;
- zspan->zbuflinefunc= zbufline;
}
- for(i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
+ /* 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;
- if(obi->flag & R_TRANSFORMED)
- zbuf_make_winmat(&R, obi->mat, winmat);
- else
- zbuf_make_winmat(&R, NULL, winmat);
+ /* filling methods */
+ for(zsample=0; zsample<samples; zsample++) {
+ zspan= &zspans[zsample];
- zbuf_project_cache_clear(cache, obr->totvert);
+ if(zmaskpass && neg_zmask)
+ zspan->zbuffunc= zbuffillGLinv4;
+ else
+ zspan->zbuffunc= zbuffillGL4;
+ zspan->zbuflinefunc= zbufline;
+ }
- for(v=0; v<obr->totvlak; v++) {
- if((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
+ /* regular zbuffering loop, does all sample buffers */
+ for(i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
+ obr= obi->obr;
- /* three cases, visible for render, only z values and nothing */
- if(vlr->lay & lay) {
- if(vlr->mat!=ma) {
- ma= vlr->mat;
- nofill= ma->mode & (MA_ZTRA|MA_ONLYCAST);
- env= (ma->mode & MA_ENV);
- wire= (ma->mode & MA_WIRE);
-
- for(zsample=0; zsample<samples; zsample++) {
- if(ma->mode & MA_ZINV) zspans[zsample].zbuffunc= zbuffillGLinv4;
- else zspans[zsample].zbuffunc= zbuffillGL4;
- }
- }
- }
- else if(all_z) {
- env= 1;
- nofill= 0;
- ma= NULL;
- }
- else {
- nofill= 1;
- ma= NULL; /* otherwise nofill can hang */
+ /* 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)
+ zbuf_make_winmat(&R, obi->mat, winmat);
+ else
+ zbuf_make_winmat(&R, NULL, winmat);
- 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, winmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, winmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, winmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if(v4) {
- c4= zbuf_part_project(cache, v4->index, winmat, bounds, v4->co, ho4);
- partclip &= c4;
+ if(clip_render_object(obi->obr->boundbox, bounds, winmat))
+ 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_ZTRA|MA_ONLYCAST);
+ env= (ma->mode & MA_ENV);
+ wire= (ma->mode & MA_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(partclip==0) {
+ if(!(vlr->flag & R_HIDDEN) && nofill==0) {
+ unsigned short partclip;
- if(env) zvlnr= -1;
- else zvlnr= v+1;
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+
+ c1= zbuf_part_project(cache, v1->index, winmat, bounds, v1->co, ho1);
+ c2= zbuf_part_project(cache, v2->index, winmat, bounds, v2->co, ho2);
+ c3= zbuf_part_project(cache, v3->index, winmat, bounds, v3->co, ho3);
+
+ /* partclipping doesn't need viewplane clipping */
+ partclip= c1 & c2 & c3;
+ if(v4) {
+ c4= zbuf_part_project(cache, v4->index, winmat, bounds, v4->co, ho4);
+ partclip &= c4;
+ }
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
- if(v4)
- c4= testclip(ho4);
+ if(partclip==0) {
+
+ if(env) zvlnr= -1;
+ else zvlnr= v+1;
- for(zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
+ c1= testclip(ho1);
+ c2= testclip(ho2);
+ c3= testclip(ho3);
+ if(v4)
+ c4= testclip(ho4);
- 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, 0, 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);
+ 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, 0, c1, c2, c3, 0);
}
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);
+ /* 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++) {
@@ -2092,6 +2263,8 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag, void(*fillfu
MEM_freeN(zspan->rectz);
MEM_freeN(zspan->rectp);
MEM_freeN(zspan->recto);
+ if(zspan->rectmask)
+ MEM_freeN(zspan->rectmask);
}
zbuf_free_span(zspan);
@@ -2115,7 +2288,7 @@ static int hashlist_projectvert(float *v1, float winmat[][4], float *hoco)
return 0;
}
- buck= &bucket[ (((long)v1)/16) & 255 ];
+ buck= &bucket[ (((intptr_t)v1)/16) & 255 ];
if(buck->vert==v1) {
QUATCOPY(hoco, buck->hoco);
return buck->clip;
@@ -2191,7 +2364,7 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem, Re
else { /* radio render */
ObjectRen *obr;
VlakRen *vlr=NULL;
- RadFace *rf;
+ RadFace **radface, *rf;
int totface=0;
/* note: radio render doesn't support duplis */
@@ -2201,8 +2374,8 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem, Re
for(a=0; a<obr->totvlak; a++) {
if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
- if(vlr->radface) {
- rf= vlr->radface;
+ if((radface=RE_vlakren_get_radface(obr, vlr, 0)) && *radface) {
+ rf= *radface;
if( (rf->flag & RAD_SHOOT)==0 ) { /* no shootelement */
if( rf->flag & RAD_TWOSIDED) zvlnr= totface;
@@ -2243,10 +2416,11 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
StrandSegment sseg;
StrandRen *strand= NULL;
StrandVert *svert;
+ StrandBound *sbound;
float obwinmat[4][4], ho1[4], ho2[4], ho3[4], ho4[4];
- int a, b, i, c1, c2, c3, c4, ok=1, lay= -1;
+ int a, b, c, i, c1, c2, c3, c4, ok=1, lay= -1;
- if(lar->mode & LA_LAYER) lay= lar->lay;
+ 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);
@@ -2272,12 +2446,17 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
if(obr->ob==re->excludeob)
continue;
+ else if(!(obi->lay & lay))
+ continue;
if(obi->flag & R_TRANSFORMED)
Mat4MulMat4(obwinmat, obi->mat, winmat);
else
Mat4CpyMat4(obwinmat, winmat);
+ if(clip_render_object(obi->obr->boundbox, NULL, obwinmat))
+ continue;
+
zbuf_project_cache_clear(cache, obr->totvert);
/* faces */
@@ -2293,7 +2472,7 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
if((ma->mode & MA_SHADBUF)==0) ok= 0;
}
- if(ok && (vlr->lay & lay) && !(vlr->flag & R_HIDDEN)) {
+ 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);
@@ -2321,45 +2500,54 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
}
/* strands */
- for(a=0; a<obr->totstrand; a++) {
- if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
-
- sseg.obi= obi;
- sseg.buffer= strand->buffer;
- sseg.sqadaptcos= sseg.buffer->adaptcos;
- sseg.sqadaptcos *= sseg.sqadaptcos;
- sseg.strand= strand;
- svert= strand->vert;
+ 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->mode & MA_SHADBUF)==0) ok= 0;
+ }
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if(sseg.buffer->ma!= ma) {
- ma= sseg.buffer->ma;
- ok= 1;
- if((ma->mode & MA_SHADBUF)==0) ok= 0;
- }
+ if(ok && (sseg.buffer->lay & lay)) {
+ zbuf_project_cache_clear(cache, strand->totvert);
- 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;
- 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);
- 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(!(c1 & c2 & c3 & c4))
- render_strand_segment(NULL, winmat, NULL, &zspan, &sseg);
+ if((a & 255)==255 && re->test_break())
+ break;
}
}
-
- if((a & 255)==255 && re->test_break())
- break;
}
if(re->test_break())
@@ -2495,11 +2683,17 @@ void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(vo
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)
zbuf_make_winmat(&R, obi->mat, winmat);
else
zbuf_make_winmat(&R, NULL, winmat);
+ if(clip_render_object(obi->obr->boundbox, bounds, winmat))
+ continue;
+
zbuf_project_cache_clear(cache, obr->totvert);
for(v=0; v<obr->totvlak; v++) {
@@ -2508,7 +2702,7 @@ void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(vo
if(material_in_material(vlr->mat, sss_ma)) {
/* three cases, visible for render, only z values and nothing */
- if(vlr->lay & lay) {
+ if(obi->lay & lay) {
if(vlr->mat!=ma) {
ma= vlr->mat;
nofill= ma->mode & MA_ONLYCAST;
@@ -2762,14 +2956,46 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove)
}
}
+/* in: two vectors, first vector points from origin back in time, 2nd vector points to future */
+/* we make this into 3 points, center point is (0,0) */
+/* and offset the center point just enough to make curve go through midpoint */
+
+static void quad_bezier_2d(float *result, float *v1, float *v2, float *ipodata)
+{
+ float p1[2], p2[2], p3[2];
+
+ p3[0]= -v2[0];
+ p3[1]= -v2[1];
+
+ p1[0]= v1[0];
+ p1[1]= v1[1];
+
+ /* official formula 2*p2 - .5*p1 - .5*p3 */
+ p2[0]= -0.5*p1[0] - 0.5*p3[0];
+ p2[1]= -0.5*p1[1] - 0.5*p3[1];
+
+ result[0]= ipodata[0]*p1[0] + ipodata[1]*p2[0] + ipodata[2]*p3[0];
+ result[1]= ipodata[0]*p1[1] + ipodata[1]*p2[1] + ipodata[2]*p3[1];
+}
+
+static void set_quad_bezier_ipo(float fac, float *data)
+{
+ float mfac= (1.0f-fac);
+
+ data[0]= mfac*mfac;
+ data[1]= 2.0f*mfac*fac;
+ data[2]= fac*fac;
+}
+
void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect)
{
ZSpan zspan;
DrawBufPixel *rectdraw, *dr;
- static float jit[16][2];
+ static float jit[256][2];
float v1[3], v2[3], v3[3], v4[3], fx, fy;
- float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz1, *dz2, *rectz, *minvecbufrect= NULL;
- float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed;
+ float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz, *dz1, *dz2, *rectz;
+ float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm, *ro;
+ float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed, totfac;
int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples;
int tsktsk= 0;
static int firsttime= 1;
@@ -2788,6 +3014,9 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
rectmove= MEM_mapallocN(xsize*ysize, "rectmove");
rectdraw= MEM_mapallocN(sizeof(DrawBufPixel)*xsize*ysize, "rect draw");
zspan.rectp= (int *)rectdraw;
+
+ rectweight= MEM_mapallocN(sizeof(float)*xsize*ysize, "rect weight");
+ rectmax= MEM_mapallocN(sizeof(float)*xsize*ysize, "rect max");
/* debug... check if PASS_VECTOR_MAX still is in buffers */
dvec1= vecbufrect;
@@ -2830,29 +3059,21 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
}
/* make vertex buffer with averaged speed and zvalues */
- rectvz= MEM_mapallocN(5*sizeof(float)*(xsize+1)*(ysize+1), "vertices");
+ rectvz= MEM_mapallocN(4*sizeof(float)*(xsize+1)*(ysize+1), "vertices");
dvz= rectvz;
for(y=0; y<=ysize; y++) {
- if(y==0) {
+ if(y==0)
dvec1= vecbufrect + 4*y*xsize;
- dz1= zbufrect + y*xsize;
- }
- else {
+ else
dvec1= vecbufrect + 4*(y-1)*xsize;
- dz1= zbufrect + (y-1)*xsize;
- }
- if(y==ysize) {
+ if(y==ysize)
dvec2= vecbufrect + 4*(y-1)*xsize;
- dz2= zbufrect + (y-1)*xsize;
- }
- else {
+ else
dvec2= vecbufrect + 4*y*xsize;
- dz2= zbufrect + y*xsize;
- }
- for(x=0; x<=xsize; x++, dz1++, dz2++) {
+ for(x=0; x<=xsize; x++) {
/* two vectors, so a step loop */
for(step=0; step<2; step++, dvec1+=2, dvec2+=2, dvz+=2) {
@@ -2910,30 +3131,21 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
}
}
}
- /* the z coordinate */
- if(x!=0) {
- if(x!=xsize)
- dvz[0]= 0.25f*(dz1[-1] + dz2[-1] + dz1[0] + dz2[0]);
- else dvz[0]= 0.5f*(dz1[0] + dz2[0]);
- }
- else dvz[0]= 0.5f*(dz1[-1] + dz2[-1]);
-
- dvz++;
}
}
/* set border speeds to keep border speeds on border */
dz1= rectvz;
- dz2= rectvz+5*(ysize)*(xsize+1);
- for(x=0; x<=xsize; x++, dz1+=5, dz2+=5) {
+ dz2= rectvz+4*(ysize)*(xsize+1);
+ for(x=0; x<=xsize; x++, dz1+=4, dz2+=4) {
dz1[1]= 0.0f;
dz2[1]= 0.0f;
dz1[3]= 0.0f;
dz2[3]= 0.0f;
}
dz1= rectvz;
- dz2= rectvz+5*(xsize);
- for(y=0; y<=ysize; y++, dz1+=5*(xsize+1), dz2+=5*(xsize+1)) {
+ dz2= rectvz+4*(xsize);
+ for(y=0; y<=ysize; y++, dz1+=4*(xsize+1), dz2+=4*(xsize+1)) {
dz1[0]= 0.0f;
dz2[0]= 0.0f;
dz1[2]= 0.0f;
@@ -2944,7 +3156,7 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
dm= rectmove;
dvec1= vecbufrect;
for(x=xsize*ysize; x>0; x--, dm++, dvec1+=4) {
- if(dvec1[0]!=0.0f || dvec1[1]!=0.0f || dvec1[2]!=0.0f || dvec1[3]!=0.0f)
+ if((dvec1[0]!=0.0f || dvec1[1]!=0.0f || dvec1[2]!=0.0f || dvec1[3]!=0.0f))
*dm= 255;
}
@@ -2953,17 +3165,20 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
/* has to become static, the init-jit calls a random-seed, screwing up texture noise node */
if(firsttime) {
firsttime= 0;
- BLI_initjit(jit[0], 16);
+ BLI_initjit(jit[0], 256);
}
+ memset(newrect, 0, sizeof(float)*xsize*ysize*4);
+ totfac= 0.0f;
+
/* accumulate */
samples/= 2;
for(step= 1; step<=samples; step++) {
float speedfac= 0.5f*nbd->fac*(float)step/(float)(samples+1);
- float blendfac= 1.0f/(ABS(step)+1);
- int side, z= 4;
+ int side;
for(side=0; side<2; side++) {
+ float blendfac, ipodata[4];
/* clear zbuf, if we draw future we fill in not moving pixels */
if(0)
@@ -2981,58 +3196,111 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
dimg= imgrect;
dm= rectmove;
+ dz= zbufrect;
dz1= rectvz;
- dz2= rectvz + 5*(xsize + 1);
+ dz2= rectvz + 4*(xsize + 1);
if(side) {
- dz1+= 2;
- dz2+= 2;
- z= 2;
+ if(nbd->curved==0) {
+ dz1+= 2;
+ dz2+= 2;
+ }
speedfac= -speedfac;
}
-
- for(fy= -0.5f+jit[step & 15][0], y=0; y<ysize; y++, fy+=1.0f) {
- for(fx= -0.5f+jit[step & 15][1], x=0; x<xsize; x++, fx+=1.0f, dimg+=4, dz1+=5, dz2+=5, dm++) {
+
+ set_quad_bezier_ipo(0.5f + 0.5f*speedfac, ipodata);
+
+ for(fy= -0.5f+jit[step & 255][0], y=0; y<ysize; y++, fy+=1.0f) {
+ for(fx= -0.5f+jit[step & 255][1], x=0; x<xsize; x++, fx+=1.0f, dimg+=4, dz1+=4, dz2+=4, dm++, dz++) {
if(*dm>1) {
+ float jfx = fx + 0.5f;
+ float jfy = fy + 0.5f;
DrawBufPixel col;
/* make vertices */
- v1[0]= speedfac*dz1[0]+fx; v1[1]= speedfac*dz1[1]+fy; v1[2]= dz1[z];
- v2[0]= speedfac*dz1[5]+fx+1.0f; v2[1]= speedfac*dz1[6]+fy; v2[2]= dz1[z+5];
- v3[0]= speedfac*dz2[5]+fx+1.0f; v3[1]= speedfac*dz2[6]+fy+1.0f; v3[2]= dz2[z+5];
- v4[0]= speedfac*dz2[0]+fx; v4[1]= speedfac*dz2[1]+fy+1.0f; v4[2]= dz2[z];
-
+ if(nbd->curved) { /* curved */
+ quad_bezier_2d(v1, dz1, dz1+2, ipodata);
+ v1[0]+= jfx; v1[1]+= jfy; v1[2]= *dz;
+
+ quad_bezier_2d(v2, dz1+4, dz1+4+2, ipodata);
+ v2[0]+= jfx+1.0f; v2[1]+= jfy; v2[2]= *dz;
+
+ quad_bezier_2d(v3, dz2+4, dz2+4+2, ipodata);
+ v3[0]+= jfx+1.0f; v3[1]+= jfy+1.0f; v3[2]= *dz;
+
+ quad_bezier_2d(v4, dz2, dz2+2, ipodata);
+ v4[0]+= jfx; v4[1]+= jfy+1.0f; v4[2]= *dz;
+ }
+ else {
+ v1[0]= speedfac*dz1[0]+jfx; v1[1]= speedfac*dz1[1]+jfy; v1[2]= *dz;
+ v2[0]= speedfac*dz1[4]+jfx+1.0f; v2[1]= speedfac*dz1[5]+jfy; v2[2]= *dz;
+ v3[0]= speedfac*dz2[4]+jfx+1.0f; v3[1]= speedfac*dz2[5]+jfy+1.0f; v3[2]= *dz;
+ v4[0]= speedfac*dz2[0]+jfx; v4[1]= speedfac*dz2[1]+jfy+1.0f; v4[2]= *dz;
+ }
if(*dm==255) col.alpha= 1.0f;
else if(*dm<2) col.alpha= 0.0f;
else col.alpha= ((float)*dm)/255.0f;
col.colpoin= dimg;
-
+
zbuf_fill_in_rgba(&zspan, &col, v1, v2, v3, v4);
}
}
- dz1+=5;
- dz2+=5;
+ dz1+=4;
+ dz2+=4;
}
-
+
+ /* blend with a falloff. this fixes the ugly effect you get with
+ * a fast moving object. then it looks like a solid object overlayed
+ * over a very transparent moving version of itself. in reality, the
+ * whole object should become transparent if it is moving fast, be
+ * we don't know what is behind it so we don't do that. this hack
+ * overestimates the contribution of foreground pixels but looks a
+ * bit better without a sudden cutoff. */
+ blendfac= ((samples - step)/(float)samples);
+ /* smoothstep to make it look a bit nicer as well */
+ blendfac= 3.0f*pow(blendfac, 2.0f) - 2.0f*pow(blendfac, 3.0f);
+
/* accum */
- for(dr= rectdraw, dz2=newrect, x= xsize*ysize-1; x>=0; x--, dr++, dz2+=4) {
+ rw= rectweight;
+ rm= rectmax;
+ for(dr= rectdraw, dz2=newrect, x= xsize*ysize-1; x>=0; x--, dr++, dz2+=4, rw++, rm++) {
if(dr->colpoin) {
float bfac= dr->alpha*blendfac;
- float mf= 1.0f - bfac;
- dz2[0]= mf*dz2[0] + bfac*dr->colpoin[0];
- dz2[1]= mf*dz2[1] + bfac*dr->colpoin[1];
- dz2[2]= mf*dz2[2] + bfac*dr->colpoin[2];
- dz2[3]= mf*dz2[3] + bfac*dr->colpoin[3];
+ dz2[0] += bfac*dr->colpoin[0];
+ dz2[1] += bfac*dr->colpoin[1];
+ dz2[2] += bfac*dr->colpoin[2];
+ dz2[3] += bfac*dr->colpoin[3];
+
+ *rw += bfac;
+ *rm= MAX2(*rm, bfac);
}
}
}
}
+ /* blend between original images and accumulated image */
+ rw= rectweight;
+ rm= rectmax;
+ ro= imgrect;
+ dm= rectmove;
+ for(dz2=newrect, x= xsize*ysize-1; x>=0; x--, dz2+=4, ro+=4, rw++, rm++, dm++) {
+ float mfac = *rm;
+ float fac = (*rw == 0.0f)? 0.0f: mfac/(*rw);
+ float nfac = 1.0f - mfac;
+
+ dz2[0]= fac*dz2[0] + nfac*ro[0];
+ dz2[1]= fac*dz2[1] + nfac*ro[1];
+ dz2[2]= fac*dz2[2] + nfac*ro[2];
+ dz2[3]= fac*dz2[3] + nfac*ro[3];
+ }
+
MEM_freeN(rectz);
MEM_freeN(rectmove);
MEM_freeN(rectdraw);
MEM_freeN(rectvz);
+ MEM_freeN(rectweight);
+ MEM_freeN(rectmax);
if(minvecbufrect) MEM_freeN(vecbufrect); /* rects were swapped! */
zbuf_free_span(&zspan);
}
@@ -3043,18 +3311,21 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
* Copy results from the solid face z buffering to the transparent
* buffer.
*/
-static void copyto_abufz(RenderPart *pa, int *arectz, int sample)
+static void copyto_abufz(RenderPart *pa, int *arectz, int *rectmask, int sample)
{
PixStr *ps;
- int x, y, *rza;
- long *rd;
+ int x, y, *rza, *rma;
+ intptr_t *rd;
if(R.osa==0) {
- memcpy(arectz, pa->rectz, 4*pa->rectx*pa->recty);
+ 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;
}
rza= arectz;
+ rma= rectmask;
rd= pa->rectdaps;
sample= (1<<sample);
@@ -3063,17 +3334,19 @@ static void copyto_abufz(RenderPart *pa, int *arectz, int sample)
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;
}
}
}
- rd++; rza++;
+ rd++; rza++, rma++;
}
}
}
@@ -3085,7 +3358,7 @@ static void copyto_abufz(RenderPart *pa, int *arectz, int sample)
* Do accumulation z buffering.
*/
-static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay)
+static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, RenderLayer *rl, unsigned int lay)
{
ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
ZSpan zspans[16], *zspan; /* MAX_OSA */
@@ -3116,11 +3389,14 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
zspan->apixbuf= APixbuf;
zspan->apsmbase= apsmbase;
+ if((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
+ zspan->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectmask");
+
/* filling methods */
zspan->zbuffunc= zbuffillAc4;
zspan->zbuflinefunc= zbuflineAc;
- copyto_abufz(pa, zspan->arectz, zsample); /* init zbuffer */
+ copyto_abufz(pa, zspan->arectz, zspan->rectmask, zsample); /* init zbuffer */
zspan->mask= 1<<zsample;
if(R.osa) {
@@ -3138,7 +3414,6 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
/* to center the sample position */
zspan->zofsx -= 0.5f;
zspan->zofsy -= 0.5f;
-
}
/* we use this to test if nothing was filled in */
@@ -3147,11 +3422,17 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
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)
zbuf_make_winmat(&R, obi->mat, winmat);
else
zbuf_make_winmat(&R, NULL, winmat);
+ if(clip_render_object(obi->obr->boundbox, bounds, winmat))
+ continue;
+
zbuf_project_cache_clear(cache, obr->totvert);
for(v=0; v<obr->totvlak; v++) {
@@ -3165,7 +3446,7 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
}
if(dofill) {
- if(!(vlr->flag & R_HIDDEN) && (vlr->lay & lay)) {
+ if(!(vlr->flag & R_HIDDEN) && (obi->lay & lay)) {
unsigned short partclip;
v1= vlr->v1;
@@ -3243,6 +3524,8 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
for(zsample=0; zsample<samples; zsample++) {
zspan= &zspans[zsample];
MEM_freeN(zspan->arectz);
+ if(zspan->rectmask)
+ MEM_freeN(zspan->rectmask);
zbuf_free_span(zspan);
}
@@ -3253,7 +3536,7 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
/* 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 */
-void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, long *rdrect)
+void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, intptr_t *rdrect)
{
RenderPass *rpass;
@@ -3287,20 +3570,15 @@ void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, lo
}
}
-static void add_transp_obindex(RenderLayer *rl, int offset, int obi, int facenr)
+static void add_transp_obindex(RenderLayer *rl, int offset, Object *ob)
{
- ObjectRen *obr= R.objectinstance[obi].obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (facenr-1) & RE_QUAD_MASK);
-
- if(vlr && obr->ob) {
- RenderPass *rpass;
-
- for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if(rpass->passtype == SCE_PASS_INDEXOB) {
- float *fp= rpass->rect + offset;
- *fp= (float)obr->ob->index;
- break;
- }
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ if(rpass->passtype == SCE_PASS_INDEXOB) {
+ float *fp= rpass->rect + offset;
+ *fp= (float)ob->index;
+ break;
}
}
}
@@ -3315,7 +3593,7 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *col= NULL;
- int pixsize= 0;
+ int pixsize= 3;
switch(rpass->passtype) {
case SCE_PASS_RGBA:
@@ -3346,6 +3624,14 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
case SCE_PASS_NORMAL:
col= shr->nor;
break;
+ case SCE_PASS_MIST:
+ col= &shr->mist;
+ pixsize= 1;
+ break;
+ case SCE_PASS_Z:
+ col= &shr->z;
+ pixsize= 1;
+ break;
case SCE_PASS_VECTOR:
{
@@ -3378,14 +3664,18 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
for(samp= 1; samp<R.osa; samp++, fp+=delta) {
col[0]+= fp[0];
- col[1]+= fp[1];
- col[2]+= fp[2];
- if(pixsize) col[3]+= fp[3];
+ if(pixsize>1) {
+ col[1]+= fp[1];
+ col[2]+= fp[2];
+ if(pixsize==4) col[3]+= fp[3];
+ }
}
col[0]*= weight;
- col[1]*= weight;
- col[2]*= weight;
- if(pixsize) col[3]*= weight;
+ if(pixsize>1) {
+ col[1]*= weight;
+ col[2]*= weight;
+ if(pixsize==4) col[3]*= weight;
+ }
}
}
@@ -3397,8 +3687,14 @@ void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alph
for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *fp, *col= NULL;
+ int pixsize= 3;
switch(rpass->passtype) {
+ case SCE_PASS_Z:
+ fp= rpass->rect + offset;
+ if(shr->z < *fp)
+ *fp= shr->z;
+ break;
case SCE_PASS_RGBA:
fp= rpass->rect + 4*offset;
addAlphaOverFloat(fp, shr->col);
@@ -3427,23 +3723,30 @@ void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alph
case SCE_PASS_NORMAL:
col= shr->nor;
break;
+ case SCE_PASS_MIST:
+ col= &shr->mist;
+ pixsize= 1;
+ break;
}
if(col) {
- fp= rpass->rect + 3*offset;
- fp[0]= alpha*col[0] + (1.0f-alpha)*fp[0];
- fp[1]= alpha*col[1] + (1.0f-alpha)*fp[1];
- fp[2]= alpha*col[2] + (1.0f-alpha)*fp[2];
+ 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)
@@ -3455,6 +3758,56 @@ static int vergzvlak(const void *a1, const void *a2)
return 0;
}
+static void shade_strand_samples(StrandShadeCache *cache, ShadeSample *ssamp, int x, int 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, svert);
+ strand_shade_unref(cache, 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;
@@ -3481,8 +3834,8 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int
shi++;
}
shi->mask= (1<<samp);
- shi->samplenr= ssamp->samplenr++;
- shade_input_set_viewco(shi, xs, ys, (float)z);
+ 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);
@@ -3501,8 +3854,8 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int
ys= (float)y + 0.5f;
}
shi->mask= curmask;
- shi->samplenr= ssamp->samplenr++;
- shade_input_set_viewco(shi, xs, ys, (float)z);
+ 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);
}
@@ -3512,8 +3865,13 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int
}
}
-static int shade_tra_samples(ShadeSample *ssamp, int x, int y, ZTranspRow *row)
+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) {
@@ -3548,7 +3906,7 @@ static void addvecmul(float *v1, float *v2, float fac)
v1[2]= v1[2]+fac*v2[2];
}
-int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
+static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
{
int a, sample, osa = (R.osa? R.osa: 1), retval = osa;
@@ -3563,6 +3921,8 @@ int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
addAlphaUnderFloat(samp_shr->combined, shr->combined);
+ samp_shr->z= MIN2(samp_shr->z, shr->z);
+
if(addpassflag & SCE_PASS_VECTOR) {
QUATCOPY(samp_shr->winspeed, shr->winspeed);
}
@@ -3595,6 +3955,10 @@ int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
if(addpassflag & SCE_PASS_RADIO)
addvecmul(samp_shr->rad, shr->rad, fac);
+
+ if(addpassflag & SCE_PASS_MIST)
+ samp_shr->mist= samp_shr->mist+fac*shr->mist;
+
}
}
}
@@ -3604,7 +3968,7 @@ int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
return retval;
}
-void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf)
+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 */
@@ -3627,23 +3991,27 @@ void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf)
#define MAX_ZROW 2000
-/* main render call to fill in pass the full transparent layer */
+/* 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)
+unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass, ListBase *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];
- float sampalpha, *passrect= pass;
- long *rdrect;
- int x, y, crop=0, a, totface;
- int addpassflag, offs= 0, od, addzbuf;
- unsigned short *ztramask= NULL;
-
+ 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())
return NULL;
@@ -3655,14 +4023,14 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
}
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_Z|SCE_PASS_COMBINED);
- if((rl->layflag & SCE_LAY_STRAND) && R.totstrand)
- addzbuf= 1; /* strands layer needs the z-buffer */
- else
- addzbuf= rl->passflag & SCE_PASS_Z;
+ addpassflag= rl->passflag & ~(SCE_PASS_COMBINED);
if(R.osa)
sampalpha= 1.0f/(float)R.osa;
@@ -3670,28 +4038,42 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
sampalpha= 1.0f;
/* fill the Apixbuf */
- if(0 == zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay)) {
+ doztra= 0;
+ if(rl->layflag & SCE_LAY_ZTRA)
+ doztra+= zbuffer_abuf(pa, APixbuf, &apsmbase, rl, rl->lay);
+ if((rl->layflag & SCE_LAY_STRAND) && APixbufstrand)
+ doztra+= zbuffer_strands_abuf(&R, pa, rl, APixbufstrand, &apsmbase, 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))
+ 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)
- reset_sky_speedvectors(pa, rl, rl->acolrect);
+ reset_sky_speedvectors(pa, rl, rl->acolrect?rl->acolrect:rl->rectf); /* if acolrect is set we use it */
/* filtered render, for now we assume only 1 filter size */
if(pa->crop) {
@@ -3699,6 +4081,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
offs= pa->rectx + 1;
passrect+= 4*offs;
aprect+= offs;
+ aprectstrand+= offs;
}
/* init scanline updates */
@@ -3710,14 +4093,15 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
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())
break;
- for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, pass+=4, od++) {
+ for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, apstrand++, pass+=4, od++) {
- if(ap->p[0]==0) {
+ if(ap->p[0]==0 && (!APixbufstrand || apstrand->p[0]==0)) {
if(addpassflag & SCE_PASS_VECTOR)
add_transp_speed(rl, od, NULL, 0.0f, rdrect);
}
@@ -3732,6 +4116,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
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;
}
@@ -3739,7 +4124,35 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
}
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]);
@@ -3750,70 +4163,110 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
qsort(zrow, totface, sizeof(ZTranspRow), vergzvlak);
}
- /* zbuffer and index pass for transparent, no AA or filters */
- if(addzbuf)
- if(pa->rectz[od]>zrow[totface-1].z)
- pa->rectz[od]= zrow[totface-1].z;
-
- if(addpassflag & SCE_PASS_INDEXOB)
- add_transp_obindex(rl, od, zrow[totface-1].obi, zrow[totface-1].p);
-
+ /* 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);
+ }
+ }
+ /* 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, x, y, &zrow[totface])) {
- if(addpassflag)
- add_transp_passes(rl, od, ssamp.shr, (1.0f-pass[3])*ssamp.shr[0].combined[3]);
-
+ 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(pass[3]>=0.999) break;
+
+ if(filled == 0) {
+ if(sscache)
+ unref_strand_samples(sscache, zrow, totface);
+ break;
+ }
}
}
- if(addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, ssamp.shr[0].winspeed, pass[3], rdrect);
+
+ 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 filled, *sp= (short *)(ztramask+od);
-
- /* for each mask-sample we alpha-under colors. then in end it's added using filter */
- memset(samp_shr, 0, sizeof(ShadeResult)*R.osa);
-
- /* nice this memset, but speed vectors are not initialized OK then. it is sufficient to only clear 1 (see merge_transp_passes) */
- if(addpassflag & SCE_PASS_VECTOR)
- samp_shr->winspeed[0]= samp_shr->winspeed[1]= samp_shr->winspeed[2]= samp_shr->winspeed[3]= PASS_VECTOR_MAX;
+ short *sp= (short *)(ztramask+od);
while(totface>0) {
totface--;
- if(shade_tra_samples(&ssamp, x, y, &zrow[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(filled==0) {
+ if(sscache)
+ unref_strand_samples(sscache, zrow, totface);
break;
+ }
}
}
- for(a=0; a<R.osa; a++) {
- add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx);
+ /* 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= ssamp.rlpp[a];
+
+ addAlphaOverFloat(rl->rectf + 4*od, samp_shr[a].combined);
+
+ add_transp_passes(rl, od, &samp_shr[a], alpha);
+ if(addpassflag & SCE_PASS_VECTOR)
+ add_transp_speed(rl, od, samp_shr[a].winspeed, alpha, rdrect);
+ }
+ }
}
-
- if(addpassflag) {
- /* merge all in one, and then add */
- merge_transp_passes(rl, samp_shr);
- add_transp_passes(rl, od, samp_shr, pass[3]);
+ else {
+ alpha= 0.0f;
- if(addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr[0].winspeed, pass[3], rdrect);
+ /* 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;
}
@@ -3822,6 +4275,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
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)
@@ -3830,45 +4287,6 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
return ztramask;
}
-/* *************** */
-
-/* uses part zbuffer values to convert into distances from camera in renderlayer */
-void convert_zbuf_to_distbuf(RenderPart *pa, RenderLayer *rl)
-{
- RenderPass *rpass;
- float *rectzf, zco;
- int a, *rectz, ortho= R.r.mode & R_ORTHO;
-
- if(pa->rectz==NULL) return;
- for(rpass= rl->passes.first; rpass; rpass= rpass->next)
- if(rpass->passtype==SCE_PASS_Z)
- break;
-
- if(rpass==NULL) {
- printf("called convert zbuf wrong...\n");
- return;
- }
-
- rectzf= rpass->rect;
- rectz= pa->rectz;
-
- for(a=pa->rectx*pa->recty; a>0; a--, rectz++, rectzf++) {
- if(*rectz>=0x7FFFFFF0)
- *rectzf= 10e10;
- else {
- /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
- /* or: (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2] - R.winmat[2][3]*zco); */
- /* if ortho [2][3] is zero, else [3][3] is zero */
-
- zco= ((float)*rectz)/2147483647.0f;
- if(ortho)
- *rectzf= (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
- else
- *rectzf= (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
- }
- }
-}
-
/* end of zbuf.c */