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>2007-12-04 16:57:28 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2007-12-04 16:57:28 +0300
commit32a8b4f8e686938ec2f0f95e6acc2eb3c25ebfdf (patch)
treeff232d89da0b2f0db1da4becb1980af513ea2274 /source/blender/render/intern
parentebfedd20b290e356f35eb1fcbcb5ddfb8e8bf0a9 (diff)
Particles
========= - Fix crash in particle transform with the particle system not editable. - Particle child distribution and caching is now multithreaded. - Child particles now have a separate Render Amount next to the existing Amount. The render amount particles are now only distributed and cached at render time, which should make editing with child particles faster. - Two new options for diffuse strand shading: - Surface Diffuse: computes the strand normal taking the normal at the surface into account. - Blending Distance: the distance in Blender units over which to blend in the normal at the surface. - Special strand rendering for more memory efficient and faster hair and grass. This is a work in progress, and has a number of known issues, don't report bugs to me for this feature yet. More info: http://www.blender.org/development/current-projects/changes-since-244/particles/
Diffstat (limited to 'source/blender/render/intern')
-rw-r--r--source/blender/render/intern/include/render_types.h42
-rw-r--r--source/blender/render/intern/include/renderdatabase.h25
-rw-r--r--source/blender/render/intern/include/shading.h5
-rw-r--r--source/blender/render/intern/include/strand.h192
-rw-r--r--source/blender/render/intern/include/zbuf.h1
-rw-r--r--source/blender/render/intern/source/convertblender.c357
-rw-r--r--source/blender/render/intern/source/envmap.c8
-rw-r--r--source/blender/render/intern/source/pipeline.c8
-rw-r--r--source/blender/render/intern/source/rendercore.c65
-rw-r--r--source/blender/render/intern/source/renderdatabase.c254
-rw-r--r--source/blender/render/intern/source/shadbuf.c2
-rw-r--r--source/blender/render/intern/source/shadeinput.c258
-rw-r--r--source/blender/render/intern/source/shadeoutput.c34
-rw-r--r--source/blender/render/intern/source/strand.c1138
-rw-r--r--source/blender/render/intern/source/zbuf.c198
15 files changed, 2434 insertions, 153 deletions
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index c20d27bfcdc..f7f2222e98d 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -48,6 +48,7 @@ struct MemArena;
struct VertTableNode;
struct VlakTableNode;
struct GHash;
+struct RenderBuckets;
#define TABLEINITSIZE 1024
#define LAMPINITSIZE 256
@@ -159,7 +160,7 @@ struct Render
float cfra;
/* render database */
- int totvlak, totvert, tothalo, totlamp;
+ int totvlak, totvert, tothalo, totstrand, totlamp;
ListBase lights; /* GroupObject pointers */
ListBase lampren; /* storage, for free */
@@ -167,9 +168,13 @@ struct Render
struct VertTableNode *vertnodes;
int vlaknodeslen;
struct VlakTableNode *vlaknodes;
+ int strandnodeslen;
+ struct StrandTableNode *strandnodes;
int blohalen;
struct HaloRen **bloha;
ListBase objecttable;
+ ListBase strandbufs;
+ struct RenderBuckets *strandbuckets;
struct Image *backbuf, *bakebuf;
@@ -234,7 +239,7 @@ typedef struct ShadBuf {
typedef struct ObjectRen {
struct ObjectRen *next, *prev;
struct Object *ob, *par;
- int index, startvert, endvert, startface, endface;
+ int index, startvert, endvert, startface, endface, startstrand, endstrand;
float *vectors;
} ObjectRen;
@@ -297,6 +302,36 @@ typedef struct HaloRen
struct Material *mat;
} HaloRen;
+typedef struct StrandVert {
+ float co[3];
+ float strandco;
+} StrandVert;
+
+typedef struct StrandBuffer {
+ struct StrandBuffer *next, *prev;
+ struct StrandVert *vert;
+ int totvert;
+
+ struct Object *ob;
+ struct Material *ma;
+ unsigned int lay;
+ int overrideuv;
+ int flag, maxdepth;
+ float adaptcos;
+
+ float winmat[4][4];
+ int winx, winy;
+} StrandBuffer;
+
+typedef struct StrandRen {
+ StrandVert *vert;
+ StrandBuffer *buffer;
+ int totvert, flag;
+ int clip, index;
+ float orco[3];
+} StrandRen;
+
+
struct LampRen;
struct MTex;
@@ -417,6 +452,9 @@ typedef struct LampRen {
#define R_SNPROJ_Z 4
#define R_FLIPPED_NO 8
+/* strandbuffer->flag */
+#define R_STRAND_BSPLINE 1
+#define R_STRAND_B_UNITS 2
#endif /* RENDER_TYPES_H */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index dc70ade25ae..febf90d9d6e 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -39,6 +39,8 @@ struct Render;
struct MCol;
struct MTFace;
struct CustomData;
+struct StrandBuffer;
+struct StrandRen;
#define RE_QUAD_MASK 0x7FFFFFF
#define RE_QUAD_OFFS 0x8000000
@@ -59,9 +61,20 @@ typedef struct VlakTableNode {
struct MTFace **mtface;
struct MCol **mcol;
int totmtface, totmcol;
+ float *surfnor;
struct CustomDataNames **names;
} VlakTableNode;
+typedef struct StrandTableNode {
+ struct StrandRen *strand;
+ float *winspeed;
+ float *surfnor;
+ struct MCol **mcol;
+ float **uv;
+ int totuv, totmcol;
+ struct CustomDataNames **names;
+} StrandTableNode;
+
typedef struct CustomDataNames{
struct CustomDataNames *next, *prev;
@@ -75,18 +88,20 @@ void free_renderdata_vertnodes(struct VertTableNode *vertnodes);
void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
void set_normalflags(Render *re);
-void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs);
+void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs, int do_buckets);
/* functions are not exported... so wrong names */
struct VlakRen *RE_findOrAddVlak(struct Render *re, int nr);
struct VertRen *RE_findOrAddVert(struct Render *re, int nr);
+struct StrandRen *RE_findOrAddStrand(struct Render *re, int nr);
struct HaloRen *RE_findOrAddHalo(struct Render *re, int nr);
struct HaloRen *RE_inithalo(struct Render *re, struct Material *ma, float *vec, float *vec1, float *orco, float hasize,
float vectsize, int seed);
struct HaloRen *RE_inithalo_particle(struct Render *re, struct DerivedMesh *dm, struct Material *ma, float *vec, float *vec1,
float *orco, float *uvco, float hasize, float vectsize, int seed);
-void RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int sve, int eve, int sfa, int efa);
+void RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int sve, int eve, int sfa, int efa, int sst, int est);
+struct StrandBuffer *RE_addStrandBuffer(struct Render *re, struct Object *ob, int totvert);
float *RE_vertren_get_sticky(struct Render *re, struct VertRen *ver, int verify);
float *RE_vertren_get_stress(struct Render *re, struct VertRen *ver, int verify);
@@ -97,6 +112,12 @@ float *RE_vertren_get_winspeed(struct Render *re, struct VertRen *ver, int verif
struct MTFace *RE_vlakren_get_tface(struct Render *re, VlakRen *ren, int n, char **name, int verify);
struct MCol *RE_vlakren_get_mcol(struct Render *re, VlakRen *ren, int n, char **name, int verify);
+float *RE_vlakren_get_surfnor(struct Render *re, VlakRen *ren, int verify);
+
+float *RE_strandren_get_winspeed(struct Render *re, struct StrandRen *strand, int verify);
+float *RE_strandren_get_surfnor(struct Render *re, struct StrandRen *strand, int verify);
+float *RE_strandren_get_uv(struct Render *re, struct StrandRen *strand, int n, char **name, int verify);
+struct MCol *RE_strandren_get_mcol(struct Render *re, struct StrandRen *strand, int n, char **name, int verify);
struct VertRen *RE_vertren_copy(struct Render *re, struct VertRen *ver);
struct VlakRen *RE_vlakren_copy(struct Render *re, struct VlakRen *vlr);
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 902899bce94..3390c32ebfe 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -29,6 +29,9 @@ struct RenderPart;
struct RenderLayer;
struct PixStr;
struct LampRen;
+struct VlakRen;
+struct StrandSegment;
+struct StrandPoint;
/* shadeinput.c */
@@ -56,6 +59,8 @@ void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z);
void shade_input_set_uv(struct ShadeInput *shi);
void shade_input_set_normals(struct ShadeInput *shi);
void shade_input_set_shade_texco(struct ShadeInput *shi);
+void shade_input_set_strand(struct ShadeInput *shi, struct StrandRen *strand, struct StrandPoint *spoint);
+void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint);
void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
new file mode 100644
index 00000000000..55c789de764
--- /dev/null
+++ b/source/blender/render/intern/include/strand.h
@@ -0,0 +1,192 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef STRAND_H
+#define STRAND_H
+
+struct StrandVert;
+struct StrandRen;
+struct StrandBuffer;
+struct ShadeSample;
+struct StrandPart;
+struct Render;
+struct RenderPart;
+struct RenderBuckets;
+struct RenderPrimitiveIterator;
+struct ZSpan;
+
+typedef struct StrandPoint {
+ /* position within segment */
+ float t;
+
+ /* camera space */
+ float co[3];
+ float nor[3];
+ float tan[3];
+ float strandco;
+ float width;
+
+ /* derivatives */
+ float dtco[3], dsco[3];
+ float dtstrandco;
+
+ /* outer points */
+ float co1[3], co2[3];
+ float hoco1[4], hoco2[4];
+ float zco1[3], zco2[3];
+
+ /* screen space */
+ float hoco[4];
+ float x, y;
+} StrandPoint;
+
+typedef struct StrandSegment {
+ struct StrandVert *v[4];
+ struct StrandRen *strand;
+ struct StrandBuffer *buffer;
+ float sqadaptcos;
+
+ StrandPoint point1, point2;
+ int shaded;
+} StrandSegment;
+
+void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
+void render_strand_segment(struct Render *re, 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);
+
+struct RenderBuckets *init_buckets(struct Render *re);
+void add_buckets_primitive(struct RenderBuckets *buckets, float *min, float *max, void *prim);
+void free_buckets(struct RenderBuckets *buckets);
+void project_hoco_to_bucket(struct RenderBuckets *buckets, float *hoco, float *bucketco);
+
+struct RenderPrimitiveIterator *init_primitive_iterator(struct Render *re, struct RenderBuckets *buckets, struct RenderPart *pa);
+void *next_primitive_iterator(struct RenderPrimitiveIterator *iter);
+void free_primitive_iterator(struct RenderPrimitiveIterator *iter);
+
+#endif
+
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef STRAND_H
+#define STRAND_H
+
+struct StrandVert;
+struct StrandRen;
+struct StrandBuffer;
+struct ShadeSample;
+struct StrandPart;
+struct Render;
+struct RenderPart;
+struct RenderBuckets;
+struct RenderPrimitiveIterator;
+struct ZSpan;
+
+typedef struct StrandPoint {
+ /* position within segment */
+ float t;
+
+ /* camera space */
+ float co[3];
+ float nor[3];
+ float tan[3];
+ float strandco;
+ float width;
+
+ /* derivatives */
+ float dtco[3], dsco[3];
+ float dtstrandco;
+
+ /* outer points */
+ float co1[3], co2[3];
+ float hoco1[4], hoco2[4];
+ float zco1[3], zco2[3];
+
+ /* screen space */
+ float hoco[4];
+ float x, y;
+} StrandPoint;
+
+typedef struct StrandSegment {
+ struct StrandVert *v[4];
+ struct StrandRen *strand;
+ struct StrandBuffer *buffer;
+ float sqadaptcos;
+
+ StrandPoint point1, point2;
+ int shaded;
+} StrandSegment;
+
+void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
+void render_strand_segment(struct Render *re, 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);
+
+struct RenderBuckets *init_buckets(struct Render *re);
+void add_buckets_primitive(struct RenderBuckets *buckets, float *min, float *max, void *prim);
+void free_buckets(struct RenderBuckets *buckets);
+void project_hoco_to_bucket(struct RenderBuckets *buckets, float *hoco, float *bucketco);
+
+struct RenderPrimitiveIterator *init_primitive_iterator(struct Render *re, struct RenderBuckets *buckets, struct RenderPart *pa);
+void *next_primitive_iterator(struct RenderPrimitiveIterator *iter);
+void free_primitive_iterator(struct RenderPrimitiveIterator *iter);
+
+#endif
+
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index ed3f93adfdd..0d88d40e7ac 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -50,6 +50,7 @@ void set_part_zbuf_clipflag(struct RenderPart *pa);
void zbuffer_shadow(struct Render *re, struct LampRen *lar, int *rectz, int size, float jitx, float jity);
void zbuffer_solid(struct RenderPart *pa, unsigned int layer, short layflag);
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);
void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int));
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index b6e0616fbbc..9bf62e52f31 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1212,12 +1212,10 @@ static void render_particle_system(Render *re, Object *ob, Object *par, PartEff
if(useFluidsimParticles) { ma->alpha = iniAlpha; }// FSPARTICLE restore...
}
-/* ------------------------------------------------------------------------- */
-
/* future thread problem... */
-static void static_particle_strand(Render *re, Object *ob, Material *ma, float *orco, float *uvco, int totuv,
- float *vec, float *vec1, float ctime, int first, int line,
- int adapt, float adapt_angle, float adapt_pix, int override_uv)
+static void static_particle_strand(Render *re, Object *ob, Material *ma, float *orco, float *surfnor,
+ float *uvco, int totuv, 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;
VlakRen *vlr;
@@ -1314,6 +1312,11 @@ static void static_particle_strand(Render *re, Object *ob, Material *ma, float *
vlr->ec= ME_V2V3;
vlr->lay= ob->lay;
+ if(surfnor) {
+ float *snor= RE_vlakren_get_surfnor(re, vlr, 1);
+ VECCOPY(snor, surfnor);
+ }
+
if(uvco){
for(i=0; i<totuv; i++){
MTFace *mtf;
@@ -1428,6 +1431,11 @@ static void static_particle_strand(Render *re, Object *ob, Material *ma, float *
vlr->ec= ME_V2V3;
vlr->lay= ob->lay;
+ if(surfnor) {
+ float *snor= RE_vlakren_get_surfnor(re, vlr, 1);
+ VECCOPY(snor, surfnor);
+ }
+
if(uvco){
for(i=0; i<totuv; i++){
MTFace *mtf;
@@ -1683,7 +1691,7 @@ static void particle_billboard(Render *re, Object *ob, Material *ma, Object *bb_
}
}
static void render_new_particle(Render *re, Object *ob, DerivedMesh *dm, Material *ma, int path, int first, int line,
- float time, float *loc, float *loc1, float *orco, int totuv, float *uvco,
+ 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)
{
HaloRen *har=0;
@@ -1695,7 +1703,7 @@ static void render_new_particle(Render *re, Object *ob, DerivedMesh *dm, Materia
if(har) har->lay= ob->lay;
}
else
- static_particle_strand(re, ob, ma, orco, uvco, totuv, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv);
+ static_particle_strand(re, ob, ma, orco, surfnor, uvco, totuv, loc, loc1, time, first, line, adapt, adapt_angle, adapt_pix, override_uv);
}
else{
har= RE_inithalo_particle(re, dm, ma, loc, NULL, orco, uvco, size, 0.0, seed);
@@ -1715,8 +1723,12 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
ParticleKey *states=0;
ParticleKey state;
ParticleCacheKey *cache=0;
- float loc[3],loc1[3],loc0[3],vel[3],imat[4][4], time;
- float *orco=0,*uvco=0;
+ StrandBuffer *strandbuf=0;
+ StrandVert *svert=0;
+ StrandRen *strand=0;
+ RNG *rng= 0;
+ float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],ornor[3],time;
+ float *orco=0,*surfnor=0,*uvco=0;
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;
int i, a, k, max_k=0, totpart, totvlako, totverto, totuv=0, override_uv=-1;
@@ -1750,15 +1762,12 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
return 0;
if(G.rendering == 0) { /* preview render */
- if(part->flag & PART_CHILD_RENDER)
- totchild = 0;
- else
- totchild = (int)((float)totchild * (float)part->disp / 100.0f);
+ totchild = (int)((float)totchild * (float)part->disp / 100.0f);
}
psys->flag|=PSYS_DRAWING;
- BLI_srandom(psys->seed);
+ rng= rng_new(psys->seed);
ma= give_render_material(re, ob, part->omat);
@@ -1773,9 +1782,15 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
RE_vlakren_set_customdata_names(re, &psmd->dm->faceData);
totuv=CustomData_number_of_layers(&psmd->dm->faceData,CD_MTFACE);
- if(ma->texco & TEXCO_UV && totuv)
+ if(ma->texco & TEXCO_UV && totuv) {
uvco = MEM_callocN(totuv*2*sizeof(float),"particle_uvs");
+ if(ma->strand_uvname[0]) {
+ override_uv= CustomData_get_named_layer_index(&psmd->dm->faceData,CD_MTFACE,ma->strand_uvname);
+ override_uv-= CustomData_get_layer_index(&psmd->dm->faceData,CD_MTFACE);
+ }
+ }
+
if(part->draw_as==PART_DRAW_BB){
int first_uv=CustomData_get_layer_index(&psmd->dm->faceData,CD_MTFACE);
@@ -1819,7 +1834,10 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
re->flag |= R_HALO;
- Mat4Invert(imat,ob->obmat);
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat); /* need to be that way, for imat texture */
+ Mat3CpyMat4(nmat, ob->imat);
+ Mat3Transp(nmat);
totvlako= re->totvlak;
totverto= re->totvert;
@@ -1838,8 +1856,8 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
//if(part->phystype==PART_PHYS_KEYED && (psys->flag&PSYS_BAKED)==0)
// path_nbr*=psys->totkeyed;
- if(path_nbr){
- if((ma->mode & (MA_HALO|MA_WIRE))==0){
+ if(path_nbr) {
+ if((ma->mode & (MA_HALO|MA_WIRE))==0) {
orco= MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
if (!re->orco_hash)
re->orco_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
@@ -1848,12 +1866,30 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
path=1;
}
- if(part->draw&PART_DRAW_REN_ADAPT){
+ if(part->draw&PART_DRAW_REN_ADAPT) {
adapt=1;
adapt_pix=(float)part->adapt_pix;
adapt_angle=cos((float)part->adapt_angle*(float)(M_PI/180.0));
}
+ if(re->r.renderer==R_INTERN && part->draw&PART_DRAW_REN_STRAND) {
+ strandbuf= RE_addStrandBuffer(re, ob, (totpart+totchild)*(path_nbr+1));
+ strandbuf->ma= ma;
+ strandbuf->lay= ob->lay;
+ Mat4CpyMat4(strandbuf->winmat, re->winmat);
+ strandbuf->winx= re->winx;
+ strandbuf->winy= re->winy;
+ strandbuf->maxdepth= 2; /* TODO */
+ strandbuf->adaptcos= cos((float)part->adapt_angle*(float)(M_PI/180.0));
+ strandbuf->overrideuv= override_uv;
+
+ 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;
+ }
}
}
else if(keys_possible && part->draw&PART_DRAW_KEYS){
@@ -1872,7 +1908,8 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
/* 3. start creating renderable things */
for(a=0,pa=pars; a<totpart+totchild; a++, pa++) {
- random = BLI_frand();
+ random = rng_getFloat(rng);
+
if(a<totpart){
if(pa->flag & PARS_UNEXIST) continue;
@@ -1895,10 +1932,10 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
/* 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,orco,0,0,0);
+ psys_particle_on_emitter(ob, psmd,tpart->from,tpa->num, -1,tpa->fuv,tpa->foffset,orco,ornor,0,0);
}
else
- psys_particle_on_emitter(ob, psmd,part->from,pa->num,-1,pa->fuv,pa->foffset,orco,0,0,0);
+ psys_particle_on_emitter(ob, psmd,part->from,pa->num,-1,pa->fuv,pa->foffset,orco,ornor,0,0);
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);
@@ -1913,8 +1950,6 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
psys_interpolate_uvs(mtface,mface->v4,pa->fuv,uvco+2*n);
}
- override_uv=CustomData_get_named_layer_index(&psmd->dm->faceData,CD_MTFACE,ma->strand_uvname)-
- CustomData_get_layer_index(&psmd->dm->faceData,CD_MTFACE);
}
pa_size=pa->size;
@@ -1930,7 +1965,8 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
}
else{
ChildParticle *cpa= psys->child+a-totpart;
- pa_time=psys_get_child_time(psys, a-totpart, cfra);
+
+ pa_time=psys_get_child_time(psys, cpa, cfra);
if((part->flag&PART_ABS_TIME)==0){
if(ma->ipo){
@@ -1945,14 +1981,14 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
}
}
- pa_size=psys_get_child_size(psys, a-totpart, cfra, &pa_time);
+ pa_size=psys_get_child_size(psys, cpa, cfra, &pa_time);
r_tilt=2.0f*cpa->rand[2];
/* 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,orco,0,0,0);
+ cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,orco,ornor,0,0);
if(uvco){
layer=psmd->dm->faceData.layers + CustomData_get_layer_index(&psmd->dm->faceData,CD_MFACE);
@@ -1991,7 +2027,7 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
}
}
- if(path_nbr){
+ if(path_nbr) {
cache = psys->childcache[a-totpart];
max_k = (int)cache->steps;
}
@@ -2003,6 +2039,36 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
orco[2] = (orco[2]-loc_tex[2])/size_tex[2];
}
+ if(ma->mode_l & MA_STR_SURFDIFF) {
+ Mat3MulVecfl(nmat, ornor);
+ surfnor= ornor;
+ }
+ else
+ surfnor= NULL;
+
+ if(strandbuf) { /* strand render */
+ strand= RE_findOrAddStrand(re, re->totstrand++);
+ strand->buffer= strandbuf;
+ strand->vert= svert;
+ VECCOPY(strand->orco, orco);
+
+ if(surfnor) {
+ float *snor= RE_strandren_get_surfnor(re, strand, 1);
+ VECCOPY(snor, surfnor);
+ }
+
+ if(uvco){
+ for(i=0; i<totuv; i++){
+ if(i != override_uv) {
+ float *uv= RE_strandren_get_uv(re, strand, i, NULL, 1);
+
+ uv[0]= uvco[2*i];
+ uv[1]= uvco[2*i+1];
+ }
+ }
+ }
+ }
+
for(k=0; k<=path_nbr; k++){
if(path_nbr){
time=(float)k/(float)path_nbr;
@@ -2026,7 +2092,7 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
if(part->draw_as!=PART_DRAW_BB)
MTC_Mat4MulVecfl(re->viewmat,loc);
- if(part->draw_as==PART_DRAW_LINE){
+ if(part->draw_as==PART_DRAW_LINE) {
VECCOPY(vel,state.vel);
//VECADD(vel,vel,state.co);
MTC_Mat4Mul3Vecfl(re->viewmat,vel);
@@ -2038,27 +2104,33 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
VECADDFAC(loc1,loc,vel,part->draw_line[1]);
render_new_particle(re,ob,psmd->dm,ma,1,0,1,0.0f,loc0,loc1,
- orco,totuv,uvco,hasize,seed,override_uv,0,0,0);
+ orco,surfnor,totuv,uvco,hasize,seed,override_uv,0,0,0);
}
- else if(part->draw_as==PART_DRAW_BB){
+ else if(part->draw_as==PART_DRAW_BB) {
VECCOPY(vel,state.vel);
//MTC_Mat4Mul3Vecfl(re->viewmat,vel);
particle_billboard(re,ob,ma,bb_ob,loc,vel,pa_size,part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt),
part->bb_align,part->draw&PART_DRAW_BB_LOCK,
a,totpart+totchild,part->bb_uv_split,part->bb_anim,part->bb_split_offset,random,pa_time,part->bb_offset,uv);
}
+ else if(strandbuf) {
+ VECCOPY(svert->co, loc);
+ svert->strandco= -1.0f + 2.0f*time;
+ svert++;
+ strand->totvert++;
+ }
else{
if(k==1){
VECSUB(loc0,loc1,loc);
VECADD(loc0,loc1,loc0);
render_new_particle(re,ob,psmd->dm,ma,path,1,0,0.0f,loc1,loc0,
- orco,totuv,uvco,hasize,seed,override_uv,
+ orco,surfnor,totuv,uvco,hasize,seed,override_uv,
adapt,adapt_angle,adapt_pix);
}
if(path_nbr==0 || k)
render_new_particle(re,ob,psmd->dm,ma,path,0,0,time,loc,loc1,
- orco,totuv,uvco,hasize,seed,override_uv,
+ orco,surfnor,totuv,uvco,hasize,seed,override_uv,
adapt,adapt_angle,adapt_pix);
VECCOPY(loc1,loc);
@@ -2067,6 +2139,9 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
if(orco1==0)
orco+=3;
+
+ if(re->test_break())
+ break;
}
/* 4. clean up */
@@ -2083,6 +2158,8 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
if(states)
MEM_freeN(states);
+
+ rng_free(rng);
psys->flag &= ~PSYS_DRAWING;
@@ -2091,9 +2168,9 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
psys->lattice=0;
}
- if(path && (ma->mode & MA_TANGENT_STR)==0)
+ if(path && (ma->mode_l & MA_TANGENT_STR)==0)
calc_vertexnormals(re, totverto, totvlako, 0);
-
+
return 1;
}
@@ -2249,7 +2326,7 @@ static void render_static_particle_system(Render *re, Object *ob, PartEff *paf)
if(ctime + paf->staticstep < mtime)
strandco= (ctime-pa->time)/(mtime-pa->time);
- static_particle_strand(re, ob, ma, orco, 0, 0, vec, vec1, strandco, first, 0,0,0,0,-1);
+ static_particle_strand(re, ob, ma, orco, 0, 0, 0, vec, vec1, strandco, first, 0,0,0,0,-1);
}
}
@@ -3704,10 +3781,11 @@ static void init_render_object(Render *re, Object *ob, Object *par, int index, i
static double lasttime= 0.0;
double time;
float mat[4][4];
- int startface, startvert, allow_render=1;
+ int startface, startvert, startstrand, allow_render=1;
startface=re->totvlak;
startvert=re->totvert;
+ startstrand=re->totstrand;
ob->flag |= OB_DONE;
@@ -3748,18 +3826,20 @@ static void init_render_object(Render *re, Object *ob, Object *par, int index, i
if(allow_render==0 && ob->type==OB_MESH)
dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- for(; psys; psys=psys->next)
+ for(; psys; psys=psys->next) {
render_new_particle_system(re, ob, psys);
+ psys_free_render_memory(ob, psys);
+ }
if(dm)
dm->release(dm);
}
/* generic post process here */
- if(startvert!=re->totvert) {
-
- RE_addRenderObject(re, ob, par, index, startvert, re->totvert, startface, re->totvlak);
+ if(startvert!=re->totvert || startstrand!=re->totstrand)
+ RE_addRenderObject(re, ob, par, index, startvert, re->totvert, startface, re->totvlak, startstrand, re->totstrand);
+ if(startvert!=re->totvert) {
/* 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 */
@@ -3778,6 +3858,7 @@ static void init_render_object(Render *re, Object *ob, Object *par, int index, i
/* clumsy copying still */
re->i.totvert= re->totvert;
re->i.totface= re->totvlak;
+ re->i.totstrand= re->totstrand;
re->i.tothalo= re->tothalo;
re->i.totlamp= re->totlamp;
re->stats_draw(&re->i);
@@ -3841,7 +3922,7 @@ void RE_Database_Free(Render *re)
free_sss(re);
- re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
re->i.convertdone= 0;
if(re->scene)
@@ -4107,7 +4188,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
/* XXX add test if dbase was filled already? */
re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
- re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
re->lights.first= re->lights.last= NULL;
re->lampren.first= re->lampren.last= NULL;
@@ -4223,7 +4304,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
Object *obd= dob->ob;
if (obd->restrictflag & OB_RESTRICT_RENDER) continue;
-
+
Mat4CpyMat4(obd->obmat, dob->mat);
/* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
@@ -4311,6 +4392,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
/* for now some clumsy copying still */
re->i.totvert= re->totvert;
re->i.totface= re->totvlak;
+ re->i.totstrand= re->totstrand;
re->i.tothalo= re->tothalo;
re->i.totlamp= re->totlamp;
re->stats_draw(&re->i);
@@ -4354,7 +4436,7 @@ 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);
+ project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
/* SSS */
if((re->r.mode & R_SSS) && !re->test_break())
@@ -4385,8 +4467,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, int timeoffset)
/* XXX add test if dbase was filled already? */
re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
- re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
- re->i.totface=re->i.totvert=re->i.totlamp=re->i.tothalo= 0;
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
+ re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0;
re->lights.first= re->lights.last= NULL;
slurph_opt= 0;
@@ -4464,14 +4546,14 @@ static void database_fromscene_vectors(Render *re, Scene *scene, int timeoffset)
}
if(!re->test_break())
- project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0);
+ project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
/* do this in end, particles for example need cfra */
G.scene->r.cfra-=timeoffset;
}
/* choose to use static, to prevent giving too many args to this call */
-static void speedvector_project(Render *re, float *zco, VertRen *ver)
+static void speedvector_project(Render *re, float *zco, float *co, float *ho)
{
static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f;
static int pano= 0;
@@ -4499,14 +4581,14 @@ static void speedvector_project(Render *re, float *zco, VertRen *ver)
}
/* now map hocos to screenspace, uses very primitive clip still */
- if(ver->ho[3]<0.1f) div= 10.0f;
- else div= 1.0f/ver->ho[3];
+ if(ho[3]<0.1f) div= 10.0f;
+ else div= 1.0f/ho[3];
/* use cylinder projection */
if(pano) {
float vec[3], ang;
- /* angle between (0,0,-1) and (ver->co) */
- VECCOPY(vec, ver->co);
+ /* angle between (0,0,-1) and (co) */
+ VECCOPY(vec, co);
ang= saacos(-vec[2]/sqrt(vec[0]*vec[0] + vec[2]*vec[2]));
if(vec[0]<0.0f) ang= -ang;
@@ -4517,57 +4599,84 @@ static void speedvector_project(Render *re, float *zco, VertRen *ver)
}
else {
- zco[0]= zmulx*(1.0f+ver->ho[0]*div);
- zco[1]= zmuly*(1.0f+ver->ho[1]*div);
+ zco[0]= zmulx*(1.0f+ho[0]*div);
+ zco[1]= zmuly*(1.0f+ho[1]*div);
+ }
+}
+
+static void calculate_speedvector(float *vectors, int step, float winsq, float winroot, float *co, float *ho, float *speed)
+{
+ float zco[2], len;
+
+ speedvector_project(NULL, zco, co, ho);
+
+ zco[0]= vectors[0] - zco[0];
+ zco[1]= vectors[1] - zco[1];
+
+ /* enable nice masks for hardly moving stuff or float inaccuracy */
+ if(zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
+ zco[0]= 0.0f;
+ zco[1]= 0.0f;
+ }
+
+ /* maximize speed for image width, otherwise it never looks good */
+ len= zco[0]*zco[0] + zco[1]*zco[1];
+ if(len > winsq) {
+ len= winroot/sqrt(len);
+ zco[0]*= len;
+ zco[1]*= len;
+ }
+
+ /* note; in main vecblur loop speedvec is negated again */
+ if(step) {
+ speed[2]= -zco[0];
+ speed[3]= -zco[1];
+ }
+ else {
+ speed[0]= zco[0];
+ speed[1]= zco[1];
}
}
-static void calculate_speedvectors(Render *re, float *vectors, int startvert, int endvert, int step)
+static void calculate_speedvectors(Render *re, ObjectRen *obren, float *vectors, int step)
{
VertRen *ver= NULL;
- float *speed, zco[2];
- float len;
+ StrandRen *strand= NULL;
+ float *speed, ho[4];
float winsq= re->winx*re->winy, winroot= sqrt(winsq);
- int a;
-
- /* set first vertex OK */
- a= startvert-1;
- ver= re->vertnodes[a>>8].vert + (a & 255);
+ int a, startvert, endvert, startstrand, endstrand;
+
+ startvert= obren->startvert;
+ endvert= obren->endvert;
+ startstrand= obren->startstrand;
+ endstrand= obren->endstrand;
- for(a=startvert; a<endvert; a++, vectors+=2) {
- if((a & 255)==0)
- ver= re->vertnodes[a>>8].vert;
- else
- ver++;
-
- speedvector_project(NULL, zco, ver);
-
- zco[0]= vectors[0] - zco[0];
- zco[1]= vectors[1] - zco[1];
-
- /* enable nice masks for hardly moving stuff or float inaccuracy */
- if(zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
- zco[0]= 0.0f;
- zco[1]= 0.0f;
- }
+ if(re->vertnodes) {
+ /* set first vertex OK */
+ a= startvert-1;
+ ver= re->vertnodes[a>>8].vert + (a & 255);
- /* maximize speed for image width, otherwise it never looks good */
- len= zco[0]*zco[0] + zco[1]*zco[1];
- if(len > winsq) {
- len= winroot/sqrt(len);
- zco[0]*= len;
- zco[1]*= len;
+ for(a=startvert; a<endvert; a++, vectors+=2) {
+ if((a & 255)==0) ver= re->vertnodes[a>>8].vert;
+ else ver++;
+
+ speed= RE_vertren_get_winspeed(re, ver, 1);
+ calculate_speedvector(vectors, step, winsq, winroot, ver->co, ver->ho, speed);
}
+ }
+
+ if(re->strandnodes) {
+ /* set first strand OK */
+ a= startstrand-1;
+ strand= re->strandnodes[a>>8].strand + (a & 255);
- speed= RE_vertren_get_winspeed(re, ver, 1);
- /* note; in main vecblur loop speedvec is negated again */
- if(step) {
- speed[2]= -zco[0];
- speed[3]= -zco[1];
- }
- else {
- speed[0]= zco[0];
- speed[1]= zco[1];
+ for(a=startstrand; a<endstrand; a++, vectors+=2) {
+ if((a & 255)==0) strand= re->strandnodes[a>>8].strand;
+ else strand++;
+
+ speed= RE_strandren_get_winspeed(re, strand, 1);
+ projectverto(strand->vert->co, re->winmat, ho);
+ calculate_speedvector(vectors, step, winsq, winroot, strand->vert->co, ho, speed);
}
}
}
@@ -4652,26 +4761,45 @@ static void copy_dbase_object_vectors(Render *re, ListBase *lb)
{
ObjectRen *obren, *obrenlb;
VertRen *ver;
- float *vec;
- int a;
-
+ StrandRen *strand;
+ float *vec, ho[4];
+ int a, totvector;
+
for(obren= re->objecttable.first; obren; obren= obren->next) {
obrenlb= MEM_dupallocN(obren);
BLI_addtail(lb, obrenlb);
- if(obren->endvert>obren->startvert) {
- vec= obrenlb->vectors= MEM_mallocN(2*sizeof(float)*(obren->endvert- obren->startvert), "vector array");
- /* first vertex */
- a= obren->startvert-1;
- ver= re->vertnodes[a>>8].vert + (a & 255);
+ totvector= obren->endvert - obren->startvert;
+ totvector+= obren->endstrand - obren->startstrand;
- for(a=obren->startvert; a<obren->endvert; a++, vec+=2) {
- if((a & 255)==0)
- ver= re->vertnodes[a>>8].vert;
- else
- ver++;
-
- speedvector_project(NULL, vec, ver);
+ if(totvector > 0) {
+ vec= obrenlb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array");
+
+ if(obren->endvert > obren->startvert) {
+ /* first vertex */
+ a= obren->startvert-1;
+ ver= re->vertnodes[a>>8].vert + (a & 255);
+
+ for(a=obren->startvert; a<obren->endvert; a++, vec+=2) {
+ if((a & 255)==0) ver= re->vertnodes[a>>8].vert;
+ else ver++;
+
+ speedvector_project(NULL, vec, ver->co, ver->ho);
+ }
+ }
+
+ if(obren->endstrand > obren->startstrand) {
+ /* first strand */
+ a= obren->startstrand-1;
+ strand= re->strandnodes[a>>8].strand + (a & 255);
+
+ for(a=obren->startstrand; a<obren->endstrand; a++, vec+=2) {
+ if((a & 255)==0) strand= re->strandnodes[a>>8].strand;
+ else strand++;
+
+ projectverto(strand->vert->co, re->winmat, ho);
+ speedvector_project(NULL, vec, strand->vert->co, ho);
+ }
}
}
}
@@ -4697,7 +4825,7 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
re->i.infostr= "Calculating previous vectors";
re->r.mode |= R_SPEED;
- speedvector_project(re, NULL, NULL); /* initializes projection code */
+ speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */
/* creates entire dbase */
database_fromscene_vectors(re, sce, -1);
@@ -4758,12 +4886,13 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
load_fluidsimspeedvectors(re, oldobren->vectors, obren->startvert, obren->endvert, step, obren->ob);
} else {
/* check if both have same amounts of vertices */
- if(obren->endvert-obren->startvert != oldobren->endvert-oldobren->startvert) {
+ if(obren->endvert-obren->startvert != oldobren->endvert-oldobren->startvert ||
+ obren->endstrand-obren->startstrand != oldobren->endstrand-oldobren->startstrand) {
printf("Warning: object %s has different amount of vertices on other frame\n", obren->ob->id.name+2);
continue;
}
- calculate_speedvectors(re, oldobren->vectors, obren->startvert, obren->endvert, step);
+ calculate_speedvectors(re, obren, oldobren->vectors, step);
} // not fluidsim
}
}
@@ -4780,7 +4909,7 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
/* exported call to recalculate hoco for vertices, when winmat changed */
void RE_DataBase_ApplyWindow(Render *re)
{
- project_renderdata(re, projectverto, 0, 0);
+ project_renderdata(re, projectverto, 0, 0, 1);
}
/* setup for shaded view or bake, so only lamps and materials are initialized */
@@ -4819,7 +4948,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
if(type!=RE_BAKE_LIGHT)
re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
- re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
re->lights.first= re->lights.last= NULL;
re->lampren.first= re->lampren.last= NULL;
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index ebb444833e8..cec96c1ab92 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -156,6 +156,9 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
envre->bloha= re->bloha;
envre->vlaknodeslen= re->vlaknodeslen;
envre->vlaknodes= re->vlaknodes;
+ envre->strandnodeslen= re->strandnodeslen;
+ envre->strandnodes= re->strandnodes;
+ envre->strandbuckets= re->strandbuckets;
envre->customdata_names= re->customdata_names;
envre->raytree= re->raytree;
@@ -176,6 +179,9 @@ static void envmap_free_render_copy(Render *envre)
envre->bloha= NULL;
envre->vlaknodeslen= 0;
envre->vlaknodes= NULL;
+ envre->strandnodeslen= 0;
+ envre->strandnodes= NULL;
+ envre->strandbuckets= NULL;
envre->customdata_names.first= envre->customdata_names.last= NULL;
envre->raytree= NULL;
@@ -403,7 +409,7 @@ static void render_envmap(Render *re, EnvMap *env)
env_rotate_scene(envre, tmat, 1);
init_render_world(envre);
- project_renderdata(envre, projectverto, 0, 0);
+ project_renderdata(envre, projectverto, 0, 0, 1);
env_layerflags(envre, env->notlay);
env_hideobject(envre, env->object);
env_set_imats(envre);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 61bc6a84556..1c3867a702c 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -171,8 +171,9 @@ void RE_FreeRenderResult(RenderResult *res)
RenderLayer *rl= res->layers.first;
if(rl->rectf) MEM_freeN(rl->rectf);
- /* acolrect is optionally allocated in shade_tile, only free here since it can be used for drawing */
+ /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */
if(rl->acolrect) MEM_freeN(rl->acolrect);
+ if(rl->scolrect) MEM_freeN(rl->scolrect);
while(rl->passes.first) {
RenderPass *rpass= rl->passes.first;
@@ -1250,6 +1251,7 @@ static void render_tile_processor(Render *re, int firsttile)
}
freeparts(re);
+ R.strandbuckets= NULL;
}
/* calculus for how much 1 pixel rendered should rotate the 3d geometry */
@@ -1307,7 +1309,7 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
Mat4CpyMat4(R.winmat, re->winmat);
/* rotate database according to part coordinates */
- project_renderdata(re, projectverto, 1, -R.panodxp*phi);
+ project_renderdata(re, projectverto, 1, -R.panodxp*phi, 1);
R.panosi= sin(R.panodxp*phi);
R.panoco= cos(R.panodxp*phi);
}
@@ -1483,7 +1485,7 @@ static void threaded_tile_processor(Render *re)
BLI_end_threads(&threads);
freeparts(re);
re->viewplane= viewplane; /* restore viewplane, modified by pano render */
-
+ R.strandbuckets= NULL;
}
/* currently only called by preview renders and envmap */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 636bee32e05..7fc4bbb3492 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -887,7 +887,7 @@ void zbufshadeDA_tile(RenderPart *pa)
if(R.flag & R_HALO)
if(rl->layflag & SCE_LAY_HALO)
halo_tile(pa, rl->rectf, rl->lay);
-
+
/* transp layer */
if(R.flag & R_ZTRA) {
if(rl->layflag & SCE_LAY_ZTRA) {
@@ -904,7 +904,7 @@ void zbufshadeDA_tile(RenderPart *pa)
/* 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;
@@ -929,6 +929,47 @@ void zbufshadeDA_tile(RenderPart *pa)
if(ztramask) MEM_freeN(ztramask);
}
}
+
+ /* strand rendering */
+ if((rl->layflag & SCE_LAY_STRAND) && R.strandbufs.first) {
+ 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);
+ }
+ }
+ 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);
+ }
+
/* sky before edge */
if(rl->layflag & SCE_LAY_SKY)
sky_tile(pa, rl->rectf);
@@ -1081,6 +1122,24 @@ void zbufshade_tile(RenderPart *pa)
}
}
}
+
+ /* strand rendering */
+ if((rl->layflag & SCE_LAY_STRAND) && R.strandbufs.first) {
+ 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);
+ }
/* sky before edge */
if(rl->layflag & SCE_LAY_SKY)
@@ -1594,7 +1653,7 @@ void add_halo_flare(Render *re)
mode= R.r.mode;
R.r.mode &= ~R_PANORAMA;
- project_renderdata(&R, projectverto, 0, 0);
+ project_renderdata(&R, projectverto, 0, 0, 0);
for(a=0; a<R.tothalo; a++) {
if((a & 255)==0) har= R.bloha[a>>8];
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 6939e70a71b..87306e9fbb5 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -79,6 +79,7 @@
#include "render_types.h"
#include "renderdatabase.h"
#include "texture.h"
+#include "strand.h"
#include "zbuf.h"
/* ------------------------------------------------------------------------- */
@@ -100,6 +101,8 @@
#define RE_WINSPEED_ELEMS 4
#define RE_MTFACE_ELEMS 1
#define RE_MCOL_ELEMS 4
+#define RE_UV_ELEMS 2
+#define RE_SURFNOR_ELEMS 3
float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify)
{
@@ -368,6 +371,21 @@ MCol *RE_vlakren_get_mcol(Render *re, VlakRen *vlr, int n, char **name, int veri
return node->mcol[index];
}
+float *RE_vlakren_get_surfnor(Render *re, VlakRen *vlak, int verify)
+{
+ float *surfnor;
+ int nr= vlak->index>>8;
+
+ surfnor= re->vlaknodes[nr].surfnor;
+ if(surfnor==NULL) {
+ if(verify)
+ surfnor= re->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
+ else
+ return NULL;
+ }
+ return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
+}
+
VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
{
VlakRen *vlr1 = RE_findOrAddVlak(re, re->totvlak++);
@@ -375,6 +393,7 @@ VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
MCol *mcol, *mcol1;
VlakTableNode *node = &re->vlaknodes[vlr->index>>8];
VlakTableNode *node1 = &re->vlaknodes[vlr1->index>>8];
+ float *surfnor, *surfnor1;
int i, index = vlr1->index;
char *name;
@@ -391,6 +410,12 @@ VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
}
+ surfnor= RE_vlakren_get_surfnor(re, vlr, 0);
+ if(surfnor) {
+ surfnor1= RE_vlakren_get_surfnor(re, vlr1, 1);
+ VECCOPY(surfnor1, surfnor);
+ }
+
if (node->names && node1->names)
node1->names[vlr1->index&255] = node->names[vlr->index&255];
@@ -480,7 +505,183 @@ VlakRen *RE_findOrAddVlak(Render *re, int nr)
/* ------------------------------------------------------------------------ */
-void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa)
+float *RE_strandren_get_winspeed(Render *re, StrandRen *strand, int verify)
+{
+ float *winspeed;
+ int nr= strand->index>>8;
+
+ winspeed= re->strandnodes[nr].winspeed;
+ if(winspeed==NULL) {
+ if(verify)
+ winspeed= re->strandnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
+ else
+ return NULL;
+ }
+ return winspeed + (strand->index & 255)*RE_WINSPEED_ELEMS;
+}
+
+float *RE_strandren_get_surfnor(Render *re, StrandRen *strand, int verify)
+{
+ float *surfnor;
+ int nr= strand->index>>8;
+
+ surfnor= re->strandnodes[nr].surfnor;
+ if(surfnor==NULL) {
+ if(verify)
+ surfnor= re->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
+ else
+ return NULL;
+ }
+ return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
+}
+
+float *RE_strandren_get_uv(Render *re, StrandRen *strand, int n, char **name, int verify)
+{
+ StrandTableNode *node;
+ int nr= strand->index>>8, strandindex= (strand->index&255);
+ int index= (n<<8) + strandindex;
+
+ node= &re->strandnodes[nr];
+
+ if(verify) {
+ if(n>=node->totuv) {
+ float **uv= node->uv;
+ int size= (n+1)*256;
+
+ node->uv= MEM_callocN(size*sizeof(MCol*), "Strand uv");
+
+ if(uv) {
+ size= node->totuv*256;
+ memcpy(node->uv, uv, size*sizeof(MCol*));
+ MEM_freeN(uv);
+ }
+
+ node->totuv= n+1;
+
+ if (!node->names) {
+ size= sizeof(*node->names)*256;
+ node->names= MEM_callocN(size, "Strand names");
+ }
+ }
+
+ if(node->uv[index]==NULL) {
+ node->uv[index]= BLI_memarena_alloc(re->memArena,
+ sizeof(float)*RE_UV_ELEMS);
+
+ node->names[strandindex]= re->customdata_names.last;
+ }
+ }
+ else {
+ if(n>=node->totuv || node->uv[index]==NULL)
+ return NULL;
+
+ if(name) *name= node->names[strandindex]->mtface[n];
+ }
+
+ return node->uv[index];
+}
+
+MCol *RE_strandren_get_mcol(Render *re, StrandRen *strand, int n, char **name, int verify)
+{
+ StrandTableNode *node;
+ int nr= strand->index>>8, strandindex= (strand->index&255);
+ int index= (n<<8) + strandindex;
+
+ node= &re->strandnodes[nr];
+
+ if(verify) {
+ if(n>=node->totmcol) {
+ MCol **mcol= node->mcol;
+ int size= (n+1)*256;
+
+ node->mcol= MEM_callocN(size*sizeof(MCol*), "Strand mcol");
+
+ if(mcol) {
+ size= node->totmcol*256;
+ memcpy(node->mcol, mcol, size*sizeof(MCol*));
+ MEM_freeN(mcol);
+ }
+
+ node->totmcol= n+1;
+
+ if (!node->names) {
+ size= sizeof(*node->names)*256;
+ node->names= MEM_callocN(size, "Strand names");
+ }
+ }
+
+ if(node->mcol[index]==NULL) {
+ node->mcol[index]= BLI_memarena_alloc(re->memArena,
+ sizeof(MCol)*RE_MCOL_ELEMS);
+
+ node->names[strandindex]= re->customdata_names.last;
+ }
+ }
+ else {
+ if(n>=node->totmcol || node->mcol[index]==NULL)
+ return NULL;
+
+ if(name) *name= node->names[strandindex]->mcol[n];
+ }
+
+ return node->mcol[index];
+}
+
+StrandRen *RE_findOrAddStrand(Render *re, int nr)
+{
+ StrandTableNode *temp;
+ StrandRen *v;
+ int a;
+
+ if(nr<0) {
+ printf("error in findOrAddStrand: %d\n",nr);
+ return re->strandnodes[0].strand;
+ }
+ a= nr>>8;
+
+ if (a>=re->strandnodeslen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= re->strandnodes;
+
+ re->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(re->strandnodeslen+TABLEINITSIZE) , "strandnodes");
+ if(temp) memcpy(re->strandnodes, temp, re->strandnodeslen*sizeof(StrandTableNode));
+ memset(re->strandnodes+re->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
+
+ re->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if(temp) MEM_freeN(temp);
+ }
+
+ v= re->strandnodes[a].strand;
+
+ if(v==NULL) {
+ int i;
+
+ v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen),"findOrAddStrand");
+ re->strandnodes[a].strand= v;
+
+ for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
+ v[a].index= i;
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+StrandBuffer *RE_addStrandBuffer(Render *re, Object *ob, int totvert)
+{
+ StrandBuffer *strandbuf;
+
+ strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
+ strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
+ strandbuf->totvert= totvert;
+ strandbuf->ob= ob;
+
+ BLI_addtail(&re->strandbufs, strandbuf);
+
+ return strandbuf;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa, int sst, int est)
{
ObjectRen *obr= MEM_mallocN(sizeof(ObjectRen), "object render struct");
@@ -492,6 +693,8 @@ void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve,
obr->endvert= eve;
obr->startface= sfa;
obr->endface= efa;
+ obr->startstrand= sst;
+ obr->endstrand= est;
}
void free_renderdata_vertnodes(VertTableNode *vertnodes)
@@ -533,6 +736,8 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes[a].mtface);
if(vlaknodes[a].mcol)
MEM_freeN(vlaknodes[a].mcol);
+ if(vlaknodes[a].surfnor)
+ MEM_freeN(vlaknodes[a].surfnor);
if(vlaknodes[a].names)
MEM_freeN(vlaknodes[a].names);
}
@@ -540,10 +745,35 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes);
}
+void free_renderdata_strandnodes(StrandTableNode *strandnodes)
+{
+ int a;
+
+ if(strandnodes==NULL) return;
+
+ for(a=0; strandnodes[a].strand; a++) {
+ MEM_freeN(strandnodes[a].strand);
+
+ if(strandnodes[a].uv)
+ MEM_freeN(strandnodes[a].uv);
+ if(strandnodes[a].mcol)
+ MEM_freeN(strandnodes[a].mcol);
+ if(strandnodes[a].winspeed)
+ MEM_freeN(strandnodes[a].winspeed);
+ if(strandnodes[a].surfnor)
+ MEM_freeN(strandnodes[a].surfnor);
+ if(strandnodes[a].names)
+ MEM_freeN(strandnodes[a].names);
+ }
+
+ MEM_freeN(strandnodes);
+}
+
void free_renderdata_tables(Render *re)
{
- int a=0;
+ StrandBuffer *strandbuf;
CustomDataNames *cdn;
+ int a=0;
if(re->bloha) {
for(a=0; re->bloha[a]; a++)
@@ -566,6 +796,17 @@ void free_renderdata_tables(Render *re)
re->vlaknodeslen= 0;
}
+ if(re->strandnodes) {
+ free_renderdata_strandnodes(re->strandnodes);
+ re->strandnodes= NULL;
+ re->strandnodeslen= 0;
+ }
+
+ if(re->strandbuckets) {
+ free_buckets(re->strandbuckets);
+ re->strandbuckets= NULL;
+ }
+
for(cdn=re->customdata_names.first; cdn; cdn=cdn->next) {
if(cdn->mtface)
MEM_freeN(cdn->mtface);
@@ -573,6 +814,10 @@ void free_renderdata_tables(Render *re)
MEM_freeN(cdn->mcol);
}
+ for(strandbuf=re->strandbufs.first; strandbuf; strandbuf=strandbuf->next)
+ if(strandbuf->vert) MEM_freeN(strandbuf->vert);
+ BLI_freelistN(&re->strandbufs);
+
BLI_freelistN(&re->customdata_names);
BLI_freelistN(&re->objecttable);
}
@@ -906,14 +1151,14 @@ static int panotestclip(Render *re, int do_pano, float *v)
- shadow buffering (shadbuf.c)
*/
-void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs)
+void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs, int do_buckets)
{
VlakRen *vlr = NULL;
VertRen *ver = NULL;
HaloRen *har = NULL;
float zn, vec[3], hoco[4];
int a;
-
+
if(do_pano) {
float panophi= xoffs;
@@ -1029,6 +1274,7 @@ void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4],
vlr->flag &= ~R_VISIBLE;
}
+ project_strands(re, projectfunc, do_pano, do_buckets);
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
index 5e010080ac0..006a26dc82e 100644
--- a/source/blender/render/intern/source/shadbuf.c
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -403,7 +403,7 @@ void makeshadowbuf(Render *re, LampRen *lar)
/* temp, will be restored */
MTC_Mat4SwapMat4(shb->persmat, re->winmat);
- project_renderdata(re, projectvert, 0, 0);
+ project_renderdata(re, projectvert, 0, 0, 0);
/* zbuffering */
rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf");
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 52a65b19824..acd04910565 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -48,6 +48,7 @@
#include "rendercore.h"
#include "shadbuf.h"
#include "shading.h"
+#include "strand.h"
#include "texture.h"
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -300,6 +301,252 @@ void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from)
memcpy(shi, from, sizeof(struct ShadeInputCopy));
}
+/* copy data from strand to shadeinput */
+void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint)
+{
+ /* note, shi->mat is set in node shaders */
+ shi->mat= shi->mat_override? shi->mat_override: strand->buffer->ma;
+
+ shi->osatex= (shi->mat->texco & TEXCO_OSA);
+ shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */
+
+ shi->puno= 0; /* always faces camera automatically */
+
+ /* shade_input_set_viewco equivalent */
+ VECCOPY(shi->co, spoint->co);
+ VECCOPY(shi->view, shi->co);
+ Normalize(shi->view);
+
+ shi->xs= (int)spoint->x;
+ shi->ys= (int)spoint->y;
+
+ if(shi->osatex || (R.r.mode & R_SHADOW)) {
+ VECCOPY(shi->dxco, spoint->dtco);
+ VECCOPY(shi->dyco, spoint->dsco);
+ }
+
+ /* dxview, dyview, not supported */
+
+ /* facenormal, simply viewco flipped */
+ VECCOPY(shi->facenor, spoint->nor);
+ VECCOPY(shi->orignor, shi->facenor);
+
+ /* shade_input_set_normals equivalent */
+ if(shi->mat->mode & MA_TANGENT_STR)
+ VECCOPY(shi->vn, spoint->tan)
+ else
+ VECCOPY(shi->vn, spoint->nor)
+
+ VECCOPY(shi->vno, shi->vn);
+}
+
+void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint)
+{
+ StrandBuffer *strandbuf= strand->buffer;
+ StrandVert *sv;
+ int mode= shi->mode; /* or-ed result for all nodes */
+ short texco= shi->mat->texco;
+
+ if((shi->mat->texco & TEXCO_REFL)) {
+ /* shi->dxview, shi->dyview, not supported */
+ }
+
+ if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL))) {
+ /* not supported */
+ }
+
+ if(mode & (MA_TANGENT_V|MA_NORMAP_TANG)) {
+ VECCOPY(shi->tang, spoint->tan);
+ }
+
+ if(mode & MA_STR_SURFDIFF) {
+ float *surfnor= RE_strandren_get_surfnor(&R, strand, 0);
+
+ if(surfnor)
+ VECCOPY(shi->surfnor, surfnor)
+ else
+ VECCOPY(shi->surfnor, shi->vn)
+
+ if(shi->mat->strand_surfnor > 0.0f) {
+ 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);
+ }
+ }
+
+ if(R.r.mode & R_SPEED) {
+ float *speed;
+
+ speed= RE_strandren_get_winspeed(&R, strand, 0);
+ if(speed)
+ QUATCOPY(shi->winspeed, speed)
+ else
+ shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f;
+ }
+
+ /* shade_input_set_shade_texco equivalent */
+ if(texco & NEED_UV) {
+ if(texco & TEXCO_ORCO) {
+ VECCOPY(shi->lo, strand->orco);
+ /* no shi->osatex, orco derivatives are zero */
+ }
+
+ if(texco & TEXCO_GLOB) {
+ VECCOPY(shi->gl, shi->co);
+ MTC_Mat4MulVecfl(R.viewinv, shi->gl);
+
+ if(shi->osatex) {
+ VECCOPY(shi->dxgl, shi->dxco);
+ MTC_Mat3MulVecfl(R.imat, shi->dxco);
+ VECCOPY(shi->dygl, shi->dyco);
+ MTC_Mat3MulVecfl(R.imat, shi->dyco);
+ }
+ }
+
+ if(texco & TEXCO_STRAND) {
+ shi->strand= spoint->strandco;
+
+ if(shi->osatex) {
+ shi->dxstrand= spoint->dtstrandco;
+ shi->dystrand= 0.0f;
+ }
+ }
+
+ if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) {
+ MCol *mcol;
+ float *uv;
+ char *name;
+ int i;
+
+ shi->totuv= 0;
+ shi->totcol= 0;
+
+ if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) {
+ for (i=0; (mcol=RE_strandren_get_mcol(&R, strand, i, &name, 0)); i++) {
+ ShadeInputCol *scol= &shi->col[i];
+ char *cp= (char*)mcol;
+
+ 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;
+ }
+
+ 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];
+ }
+ else {
+ shi->vcol[0]= 0.0f;
+ shi->vcol[1]= 0.0f;
+ shi->vcol[2]= 0.0f;
+ }
+ }
+
+ for (i=0; (uv=RE_strandren_get_uv(&R, strand, i, &name, 0)); i++) {
+ ShadeInputUV *suv= &shi->uv[i];
+
+ shi->totuv++;
+ suv->name= name;
+
+ if(strandbuf->overrideuv == i) {
+ suv->uv[0]= -1.0f;
+ suv->uv[1]= spoint->strandco;
+ suv->uv[2]= 0.0f;
+ }
+ else {
+ suv->uv[0]= -1.0f + 2.0f*uv[0];
+ suv->uv[1]= -1.0f + 2.0f*uv[1];
+ suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
+ }
+
+ if(shi->osatex) {
+ suv->dxuv[0]= 0.0f;
+ suv->dxuv[1]= 0.0f;
+ suv->dyuv[0]= 0.0f;
+ suv->dyuv[1]= 0.0f;
+ }
+
+ if((mode & MA_FACETEXTURE) && i==0) {
+ if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) {
+ shi->vcol[0]= 1.0f;
+ shi->vcol[1]= 1.0f;
+ shi->vcol[2]= 1.0f;
+ }
+ }
+ }
+
+ if(shi->totuv == 0) {
+ ShadeInputUV *suv= &shi->uv[0];
+
+ suv->uv[0]= 0.0f;
+ suv->uv[1]= spoint->strandco;
+ suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
+
+ if(mode & MA_FACETEXTURE) {
+ /* no tface? set at 1.0f */
+ shi->vcol[0]= 1.0f;
+ shi->vcol[1]= 1.0f;
+ shi->vcol[2]= 1.0f;
+ }
+ }
+
+ }
+
+ if(texco & TEXCO_NORM) {
+ shi->orn[0]= -shi->vn[0];
+ shi->orn[1]= -shi->vn[1];
+ shi->orn[2]= -shi->vn[2];
+ }
+
+ if(mode & MA_RADIO) {
+ /* not supported */
+ }
+
+ if(texco & TEXCO_REFL) {
+ /* mirror reflection color textures (and envmap) */
+ calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */
+ }
+
+ if(texco & TEXCO_STRESS) {
+ /* not supported */
+ }
+
+ if(texco & TEXCO_TANGENT) {
+ if((mode & MA_TANGENT_V)==0) {
+ /* just prevent surprises */
+ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
+ }
+ }
+ }
+
+ shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f;
+
+ /* this only avalailable for scanline renders */
+ if(shi->depth==0) {
+ if(texco & TEXCO_WINDOW) {
+ shi->winco[0]= -1.0f + 2.0f*spoint->x/(float)R.winx;
+ shi->winco[1]= -1.0f + 2.0f*spoint->y/(float)R.winy;
+ shi->winco[2]= 0.0f;
+
+ /* not supported */
+ if(shi->osatex) {
+ shi->dxwin[0]= 0.0f;
+ shi->dywin[1]= 0.0f;
+ shi->dxwin[0]= 0.0f;
+ shi->dywin[1]= 0.0f;
+ }
+ }
+
+ if(texco & TEXCO_STICKY) {
+ /* not supported */
+ }
+ }
+}
/* scanline pixel coordinates */
/* requires set_triangle */
@@ -571,6 +818,17 @@ void shade_input_set_shade_texco(ShadeInput *shi)
else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
}
}
+
+ if(mode & MA_STR_SURFDIFF) {
+ float *surfnor= RE_vlakren_get_surfnor(&R, shi->vlr, 0);
+
+ if(surfnor)
+ VECCOPY(shi->surfnor, surfnor)
+ else
+ VECCOPY(shi->surfnor, shi->vn)
+
+ shi->surfdist= 0.0f;
+ }
if(R.r.mode & R_SPEED) {
float *s1, *s2, *s3;
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index dc7dab7b1ca..037a3aa8409 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -1212,13 +1212,35 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
lacol[2]= lar->b;
if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol);
-
- /* tangent case; calculate fake face normal, aligned with lampvector */
- /* note, vnor==vn is used as tangent trigger for buffer shadow */
+
+ /* tangent case; calculate fake face normal, aligned with lampvector */
+ /* note, vnor==vn is used as tangent trigger for buffer shadow */
if(vlr->flag & R_TANGENT) {
- float cross[3];
- Crossf(cross, lv, vn);
- Crossf(vnor, cross, vn);
+ float cross[3], nstrand[3], blend;
+
+ if(ma->mode & MA_STR_SURFDIFF) {
+ Crossf(cross, shi->surfnor, vn);
+ Crossf(nstrand, vn, cross);
+
+ blend= INPR(nstrand, shi->surfnor);
+ CLAMP(blend, 0.0f, 1.0f);
+
+ VecLerpf(vnor, nstrand, shi->surfnor, blend);
+ Normalize(vnor);
+ }
+ else {
+ Crossf(cross, lv, vn);
+ Crossf(vnor, cross, vn);
+ }
+
+ if(ma->strand_surfnor > 0.0f) {
+ if(ma->strand_surfnor > shi->surfdist) {
+ blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
+ VecLerpf(vnor, vnor, shi->surfnor, blend);
+ Normalize(vnor);
+ }
+ }
+
vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
vn= vnor;
}
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
new file mode 100644
index 00000000000..95768e1a0d8
--- /dev/null
+++ b/source/blender/render/intern/source/strand.c
@@ -0,0 +1,1138 @@
+/**
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributors: Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "render_types.h"
+#include "initrender.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "renderpipeline.h"
+#include "pixelblending.h"
+#include "shading.h"
+#include "strand.h"
+#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, 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 {
+ RenderBuckets *buckets;
+ ListBase *list[6];
+ int listindex, totlist;
+ BucketPrims *bpr;
+ int bprindex;
+} 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->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];
+
+ return iter;
+}
+
+void *next_primitive_iterator(RenderPrimitiveIterator *iter)
+{
+ 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++];
+}
+
+void free_primitive_iterator(RenderPrimitiveIterator *iter)
+{
+ MEM_freeN(iter);
+}
+
+/* *************** */
+
+static float strand_eval_width(Material *ma, float strandco)
+{
+ float fac;
+
+ strandco= 0.5f*(strandco + 1.0f);
+
+ if(ma->strand_ease!=0.0f) {
+ if(ma->strand_ease<0.0f)
+ fac= pow(strandco, 1.0+ma->strand_ease);
+ else
+ fac= pow(strandco, 1.0/(1.0f-ma->strand_ease));
+ }
+ else fac= strandco;
+
+ return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
+}
+
+void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
+{
+ Material *ma;
+ StrandBuffer *strandbuf;
+ float p[4][3], data[4], cross[3], w, dx, dy, t;
+ int type;
+
+ strandbuf= sseg->buffer;
+ ma= sseg->buffer->ma;
+ t= spoint->t;
+ type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL;
+
+ VECCOPY(p[0], sseg->v[0]->co);
+ VECCOPY(p[1], sseg->v[1]->co);
+ VECCOPY(p[2], sseg->v[2]->co);
+ VECCOPY(p[3], sseg->v[3]->co);
+
+ if(t == 0.0f) {
+ VECCOPY(spoint->co, sseg->v[1]->co);
+ spoint->strandco= sseg->v[1]->strandco;
+
+ spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco);
+ if(sseg->v[0] != sseg->v[1])
+ spoint->dtstrandco *= 0.5f;
+ }
+ else if(t == 1.0f) {
+ VECCOPY(spoint->co, sseg->v[2]->co);
+ spoint->strandco= sseg->v[2]->strandco;
+
+ spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco);
+ if(sseg->v[3] != sseg->v[2])
+ spoint->dtstrandco *= 0.5f;
+ }
+ else {
+ set_four_ipo(t, data, type);
+ spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
+ spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
+ spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
+ spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco;
+ }
+
+ set_afgeleide_four_ipo(t, data, type);
+ spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
+ spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
+ spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
+
+ VECCOPY(spoint->tan, spoint->dtco);
+ Normalize(spoint->tan);
+
+ VECCOPY(spoint->nor, spoint->co);
+ VECMUL(spoint->nor, -1.0f);
+ Normalize(spoint->nor);
+
+ spoint->width= strand_eval_width(ma, spoint->strandco);
+
+ /* outer points */
+ Crossf(cross, spoint->co, spoint->tan);
+
+ if(strandbuf->flag & R_STRAND_B_UNITS)
+ Normalize(cross);
+
+ w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
+ dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
+ dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
+ w= sqrt(dx*dx + dy*dy);
+
+ if(w > 0.0f) {
+ if(strandbuf->flag & R_STRAND_B_UNITS) {
+ w= 1.0f/w;
+
+ if(spoint->width < w)
+ spoint->width= w;
+ VecMulf(cross, spoint->width*0.5f);
+ }
+ else
+ VecMulf(cross, spoint->width/w);
+ }
+
+ VecSubf(spoint->co1, spoint->co, cross);
+ VecAddf(spoint->co2, spoint->co, cross);
+
+ VECCOPY(spoint->dsco, cross);
+}
+
+/* *************** */
+
+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 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 interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
+{
+ v[0]= negt*v1[0] + t*v2[0];
+ v[1]= negt*v1[1] + t*v2[1];
+ v[2]= negt*v1[2] + t*v2[2];
+}
+
+static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v)
+{
+ v[0]= negt*v1[0] + t*v2[0];
+ v[1]= negt*v1[1] + t*v2[1];
+ v[2]= negt*v1[2] + t*v2[2];
+ v[3]= negt*v1[3] + t*v2[3];
+}
+
+static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
+{
+ float negt= 1.0f - t;
+
+ interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined);
+
+ if(addpassflag & SCE_PASS_VECTOR) {
+ interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed);
+ }
+ /* optim... */
+ if(addpassflag & ~(SCE_PASS_VECTOR)) {
+ if(addpassflag & SCE_PASS_RGBA)
+ interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col);
+ if(addpassflag & SCE_PASS_NORMAL) {
+ interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor);
+ Normalize(shr->nor);
+ }
+ if(addpassflag & SCE_PASS_DIFFUSE)
+ interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff);
+ if(addpassflag & SCE_PASS_SPEC)
+ interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec);
+ if(addpassflag & SCE_PASS_SHADOW)
+ interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad);
+ if(addpassflag & SCE_PASS_AO)
+ interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao);
+ if(addpassflag & SCE_PASS_REFLECT)
+ interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl);
+ if(addpassflag & SCE_PASS_REFRACT)
+ interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
+ if(addpassflag & SCE_PASS_RADIO)
+ interpolate_vec3(shr1->rad, shr2->rad, t, negt, shr->rad);
+ }
+}
+
+static void add_strand_obindex(RenderLayer *rl, int offset, Object *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)ob->index;
+ break;
+ }
+ }
+}
+
+static void do_strand_point_project(Render *re, ZSpan *zspan, float *co, float *hoco, float *zco)
+{
+ projectvert(co, re->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;
+}
+
+#include "BLI_rand.h"
+void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint);
+
+static void strand_shade_get(StrandPart *spart, int lookup, ShadeSample *ssamp, StrandPoint *spoint, StrandVert *svert, StrandSegment *sseg)
+{
+ ShadeResult *hashshr;
+
+ if(lookup) {
+ hashshr= BLI_ghash_lookup(spart->hash, svert);
+
+ if(!hashshr) {
+ strand_shade_point(spart->re, ssamp, sseg, spoint);
+
+ 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);
+ }
+ }
+ else
+ strand_shade_point(spart->re, ssamp, sseg, spoint);
+}
+
+static void strand_shade_segment(StrandPart *spart)
+{
+ StrandSegment *sseg= spart->segment;
+ int first, last;
+
+ if(!sseg->shaded) {
+ first= (sseg->v[1] == &sseg->strand->vert[0]);
+ last= (sseg->v[2] == &sseg->strand->vert[sseg->strand->totvert-1]);
+
+ 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;
+ }
+
+#if 0
+ float c[3];
+
+ c[0]= BLI_frand();
+ c[1]= BLI_frand();
+ c[2]= BLI_frand();
+
+ spart->ssamp1.shr[0].combined[0] *= c[0];
+ spart->ssamp1.shr[0].combined[1] *= c[1];
+ spart->ssamp1.shr[0].combined[2] *= c[2];
+
+ 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
+}
+
+static void do_strand_blend(void *handle, int x, int y, float u, float v, float z)
+{
+ StrandPart *spart= (StrandPart*)handle;
+ StrandBuffer *buffer= spart->segment->buffer;
+ ShadeResult *shr;
+ float /**pass,*/ t;
+ int offset, zverg;
+
+ /* check again solid z-buffer */
+ offset = y*spart->rectx + x;
+ zverg= (int)z;
+
+ 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;
+
+ /* shade points if not shaded yet */
+ strand_shade_segment(spart);
+
+ /* 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);
+
+ /* 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);
+
+#if 0
+ /* fill in pass for preview */
+ if(spart->sample == 0) {
+ pass= spart->pass + offset*4;
+ QUATCOPY(pass, shr->combined);
+ }
+#endif
+
+ if(spart->addpassflag & SCE_PASS_INDEXOB)
+ add_strand_obindex(spart->rl, offset, buffer->ob);
+ }
+}
+
+static int strand_test_clip(Render *re, ZSpan *zspan, float *bounds, float *co, float *zcomp)
+{
+ float hoco[4];
+ int clipflag= 0;
+
+ projectvert(co, re->winmat, hoco);
+
+ /* we compare z without perspective division for segment sorting */
+ *zcomp= hoco[2];
+
+ if(hoco[0] > bounds[1]*hoco[3]) clipflag |= 1;
+ else if(hoco[0]< bounds[0]*hoco[3]) clipflag |= 2;
+ else if(hoco[1] > bounds[3]*hoco[3]) clipflag |= 4;
+ else if(hoco[1]< bounds[2]*hoco[3]) clipflag |= 8;
+
+ return clipflag;
+}
+
+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|R_VISIBLE;
+ if(sseg->buffer->ma->mode & MA_TANGENT_STR)
+ vlr.flag |= R_TANGENT;
+ shi->vlr= &vlr;
+
+ /* 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);
+
+ /* 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;
+
+ VECCOPY(jco1, co1);
+ VECCOPY(jco2, co2);
+ VECCOPY(jco3, co3);
+ VECCOPY(jco4, co4);
+
+ if(re->osa) {
+ jx= -re->jit[sample][0];
+ jy= -re->jit[sample][1];
+
+ jco1[0] += jx; jco1[1] += jy;
+ jco2[0] += jx; jco2[1] += jy;
+ jco3[0] += jx; jco3[1] += jy;
+ jco4[0] += jx; jco4[1] += jy;
+ }
+ else if(re->i.curblur) {
+ jx= -re->jit[re->i.curblur-1][0];
+ jy= -re->jit[re->i.curblur-1][1];
+
+ jco1[0] += jx; jco1[1] += jy;
+ jco2[0] += jx; jco2[1] += jy;
+ jco3[0] += jx; jco3[1] += jy;
+ jco4[0] += jx; jco4[1] += jy;
+ }
+
+ spart->sample= sample;
+
+ spart->t[0]= t-dt;
+ spart->t[1]= t-dt;
+ spart->t[2]= t;
+ zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_blend);
+ spart->t[0]= t-dt;
+ spart->t[1]= t;
+ spart->t[2]= t;
+ zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_blend);
+}
+
+static void strand_render(Render *re, StrandPart *spart, ZSpan *zspan, StrandPoint *p1, StrandPoint *p2)
+{
+ if(spart) {
+ float t= p2->t;
+ float dt= p2->t - p1->t;
+ int a;
+
+ if(re->osa) {
+ for(a=0; a<re->osa; a++)
+ do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a);
+ }
+ else
+ 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, re->winmat, hoco1);
+ projectvert(p2->co, re->winmat, hoco2);
+
+ /* render both strand and single pixel wire to counter aliasing */
+ zbufclip4(zspan, 0, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, 0, 0, 0, 0);
+ zbufsinglewire(zspan, 0, hoco1, hoco2);
+ }
+}
+
+static int strand_segment_recursive(Render *re, StrandPart *spart, ZSpan *zspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
+{
+ StrandPoint p;
+ StrandBuffer *buffer= sseg->buffer;
+ float dot, d1[2], d2[2], len1, len2;
+
+ if(depth == buffer->maxdepth)
+ return 0;
+
+ p.t= (p1->t + p2->t)*0.5f;
+ strand_eval_point(sseg, &p);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p);
+
+ d1[0]= (p.x - p1->x);
+ d1[1]= (p.y - p1->y);
+ len1= d1[0]*d1[0] + d1[1]*d1[1];
+
+ d2[0]= (p2->x - p.x);
+ d2[1]= (p2->y - p.y);
+ len2= d2[0]*d2[0] + d2[1]*d2[1];
+
+ if(len1 == 0.0f || len2 == 0.0f)
+ return 0;
+
+ dot= d1[0]*d2[0] + d1[1]*d2[1];
+ if(dot*dot > sseg->sqadaptcos*len1*len2)
+ return 0;
+
+ if(spart) {
+ do_strand_point_project(re, zspan, p.co1, p.hoco1, p.zco1);
+ do_strand_point_project(re, zspan, p.co2, p.hoco2, p.zco2);
+ }
+ else {
+ projectvert(p.co1, re->winmat, p.hoco1);
+ projectvert(p.co2, re->winmat, p.hoco2);
+ }
+
+ if(!strand_segment_recursive(re, spart, zspan, sseg, p1, &p, depth+1))
+ strand_render(re, spart, zspan, p1, &p);
+ if(!strand_segment_recursive(re, spart, zspan, sseg, &p, p2, depth+1))
+ strand_render(re, spart, zspan, &p, p2);
+
+ return 1;
+}
+
+void render_strand_segment(Render *re, StrandPart *spart, ZSpan *zspan, StrandSegment *sseg)
+{
+ StrandBuffer *buffer= sseg->buffer;
+ StrandPoint *p1= &sseg->point1;
+ StrandPoint *p2= &sseg->point2;
+
+ p1->t= 0.0f;
+ p2->t= 1.0f;
+
+ strand_eval_point(sseg, p1);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1);
+ strand_eval_point(sseg, p2);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2);
+
+ if(spart) {
+ do_strand_point_project(re, zspan, p1->co1, p1->hoco1, p1->zco1);
+ do_strand_point_project(re, zspan, p1->co2, p1->hoco2, p1->zco2);
+ do_strand_point_project(re, zspan, p2->co1, p2->hoco1, p2->zco1);
+ do_strand_point_project(re, zspan, p2->co2, p2->hoco2, p2->zco2);
+ }
+ else {
+ projectvert(p1->co1, re->winmat, p1->hoco1);
+ projectvert(p1->co2, re->winmat, p1->hoco2);
+ projectvert(p2->co1, re->winmat, p2->hoco1);
+ projectvert(p2->co2, re->winmat, p2->hoco2);
+ }
+
+ if(!strand_segment_recursive(re, spart, zspan, sseg, p1, p2, 0))
+ strand_render(re, 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;
+}
+
+/* render call to fill in strands */
+unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *rl, float *pass)
+{
+ struct RenderPrimitiveIterator *iter;
+ ZSpan zspan;
+ StrandRen *strand=0;
+ StrandVert *svert;
+ StrandPart spart;
+ StrandSegment sseg;
+ StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
+ MemArena *memarena;
+ float z[4], bounds[4];
+ int a, b, resultsize, totsegment, clip[4];
+
+ if(re->test_break())
+ return NULL;
+ if(re->strandbufs.first == NULL)
+ return NULL;
+
+ /* 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.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;
+
+ zbuf_alloc_span(&zspan, pa->rectx, pa->recty);
+
+ /* needed for transform from hoco to zbuffer co */
+ zspan.zmulx= ((float)re->winx)/2.0;
+ zspan.zmuly= ((float)re->winy)/2.0;
+
+ zspan.zofsx= -pa->disprect.xmin;
+ zspan.zofsy= -pa->disprect.ymin;
+
+ /* to center the sample position */
+ zspan.zofsx -= 0.5f;
+ zspan.zofsy -= 0.5f;
+
+ /* 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))) {
+ if(re->test_break())
+ break;
+
+ if(strand->clip)
+ continue;
+
+ svert= strand->vert;
+
+ /* keep clipping and z depth for 4 control points */
+ clip[1]= strand_test_clip(re, &zspan, bounds, svert->co, &z[1]);
+ clip[2]= strand_test_clip(re, &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(re, &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->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];
+ }
+ }
+
+ free_primitive_iterator(iter);
+
+ if(!re->test_break()) {
+ /* convert list to array and sort */
+ sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
+ for(a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
+ sortsegments[a]= *sortseg;
+ qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
+ }
+
+ BLI_memarena_free(memarena);
+
+ spart.hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ if(!re->test_break()) {
+ /* render segments in sorted order */
+ sortseg= sortsegments;
+ for(a=0; a<totsegment; a++, sortseg++) {
+ if(re->test_break())
+ break;
+
+ sseg.strand= RE_findOrAddStrand(re, sortseg->strand);
+ sseg.buffer= sseg.strand->buffer;
+ sseg.sqadaptcos= sseg.buffer->adaptcos;
+ sseg.sqadaptcos *= sseg.sqadaptcos;
+
+ svert= sseg.strand->vert + sortseg->segment;
+ sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
+ sseg.v[1]= svert;
+ sseg.v[2]= svert+1;
+ sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
+ sseg.shaded= 0;
+
+ spart.segment= &sseg;
+
+ render_strand_segment(re, &spart, &zspan, &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);
+
+ zbuf_free_span(&zspan);
+
+ if(!(re->osa && (rl->layflag & SCE_LAY_SOLID))) {
+ MEM_freeN(spart.mask);
+ spart.mask= NULL;
+ }
+
+ return spart.mask;
+}
+
+void project_strands(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int do_buckets)
+{
+ 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(do_buckets)
+ re->strandbuckets= init_buckets(re);
+
+ /* calculate view coordinates (and zbuffer value) */
+ for(a=0; a<re->totstrand; a++) {
+ if((a & 255)==0) strand= re->strandnodes[a>>8].strand;
+ else strand++;
+
+ strand->clip= ~0;
+
+#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)
+
+ 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
+
+ INIT_MINMAX2(min, max);
+ svert= strand->vert;
+ for(b=0; b<strand->totvert; b++, svert++) {
+ //VECADD(vec, svert->co, bpad);
+
+ /* 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)
+
+ /* Go from wcs to hcs ... */
+ projectfunc(vec, re->winmat, hoco);
+ /* ... and clip in that system. */
+ strand->clip &= testclip(hoco);
+
+ if(do_buckets) {
+ project_hoco_to_bucket(re->strandbuckets, hoco, bucketco);
+ DO_MINMAX2(bucketco, min, max);
+ }
+ }
+
+ if(do_buckets) {
+#if 0
+ 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;
+ }
+#endif
+
+ add_buckets_primitive(re->strandbuckets, min, max, strand);
+ }
+ }
+}
+
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 80b20a8e18e..cb92f8cefb3 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -39,8 +39,8 @@
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
-#include "BLI_threads.h"
#include "BLI_jitter.h"
+#include "BLI_threads.h"
#include "MTC_matrixops.h"
#include "MEM_guardedalloc.h"
@@ -69,6 +69,7 @@
#include "shadbuf.h"
#include "shading.h"
#include "sss.h"
+#include "strand.h"
/* own includes */
#include "zbuf.h"
@@ -861,7 +862,7 @@ static int clipline(float *v1, float *v2) /* return 0: do not draw */
return 0;
}
-static void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco)
+void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco)
{
float div;
@@ -977,6 +978,34 @@ void zbufclipwire(ZSpan *zspan, int zvlnr, VlakRen *vlr)
}
+void zbufsinglewire(ZSpan *zspan, int zvlnr, float *ho1, float *ho2)
+{
+ float f1[4], f2[4];
+ int c1, c2;
+
+ c1= testclip(ho1);
+ c2= testclip(ho2);
+
+ if(c1 | c2) { /* not in the middle */
+ if(!(c1 & c2)) { /* not out completely */
+ QUATCOPY(f1, ho1);
+ QUATCOPY(f2, ho2);
+
+ if(clipline(f1, f2)) {
+ hoco_to_zco(zspan, f1, f1);
+ hoco_to_zco(zspan, f2, f2);
+ zspan->zbuflinefunc(zspan, zvlnr, f1, f2);
+ }
+ }
+ }
+ else {
+ hoco_to_zco(zspan, f1, ho1);
+ hoco_to_zco(zspan, f2, ho2);
+
+ zspan->zbuflinefunc(zspan, zvlnr, f1, f2);
+ }
+}
+
/**
* Fill the z buffer, but invert z order, and add the face index to
* the corresponing face buffer.
@@ -1312,7 +1341,105 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, floa
}
/* 2d scanconvert for tria, calls func for each x,y coordinate and gives UV barycentrics */
-/* zspan should be initialized, has rect size and span buffers */
+void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) )
+{
+ float x0, y0, x1, y1, x2, y2, z0, z1, z2, z;
+ float u, v, uxd, uyd, vxd, vyd, uy0, vy0, zxd, zyd, zy0, xx1;
+ float *span1, *span2;
+ int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0f) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ z1= 1.0f; // (u1 - u2)
+ z2= 0.0f; // (u2 - u3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + 1.0f;
+ uxd= -(double)x0/(double)z0;
+ uyd= -(double)y0/(double)z0;
+ uy0= ((double)my2)*uyd + (double)xx1;
+
+ z1= -1.0f; // (v1 - v2)
+ z2= 1.0f; // (v2 - v3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0;
+ vxd= -(double)x0/(double)z0;
+ vyd= -(double)y0/(double)z0;
+ vy0= ((double)my2)*vyd + (double)xx1;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ u= (double)sn1*uxd + uy0;
+ v= (double)sn1*vxd + vy0;
+ z= (double)sn1*zxd + zy0;
+
+ for(x= sn1; x<=sn2; x++, u+=uxd, v+=vxd, z+=zxd)
+ func(handle, x, y, u, v, z);
+
+ uy0 -= uyd;
+ vy0 -= vyd;
+ zy0 -= zyd;
+ }
+}
+
+/* scanconvert for strand triangles, calls func for each x,y coordinate and gives UV barycentrics and z */
void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) )
{
@@ -1957,7 +2084,10 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx,
ZSpan zspan;
VlakRen *vlr= NULL;
Material *ma= NULL;
- int a, ok=1, lay= -1;
+ StrandSegment sseg;
+ StrandRen *strand= NULL;
+ StrandVert *svert;
+ int a, b, ok=1, lay= -1;
if(lar->mode & LA_LAYER) lay= lar->lay;
@@ -2002,6 +2132,39 @@ void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx,
}
}
}
+
+ /* shadow */
+ for(a=0; a<re->totstrand; a++) {
+ if((a & 255)==0) strand= re->strandnodes[a>>8].strand;
+ else strand++;
+
+ if(strand->clip)
+ continue;
+
+ 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;
+ }
+
+ if(ok && (sseg.buffer->lay & lay)) {
+ 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;
+
+ render_strand_segment(re, NULL, &zspan, &sseg);
+ }
+ }
+ }
/* merge buffers */
if(lar->buftype==LA_SHADBUF_HALFWAY) {
@@ -2019,7 +2182,6 @@ static void zbuffill_sss(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v
double zxd, zyd, zy0, z;
float x0, y0, x1, y1, x2, y2, z0, z1, z2, xx1, *span1, *span2;
int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
-
/* init */
zbuf_init_span(zspan);
@@ -2824,7 +2986,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 */
-static 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, long *rdrect)
{
RenderPass *rpass;
@@ -2852,7 +3014,6 @@ static void add_transp_speed(RenderLayer *rl, int offset, float *speed, float al
fp[2]= speed[2];
fp[3]= speed[3];
}
-
}
break;
}
@@ -2877,7 +3038,7 @@ static void add_transp_obindex(RenderLayer *rl, int offset, int facenr)
/* ONLY OSA! merge all shaderesult samples to one */
/* target should have been cleared */
-static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
+void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
{
RenderPass *rpass;
float weight= 1.0f/((float)R.osa);
@@ -2961,7 +3122,7 @@ static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
}
-static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha)
+void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha)
{
RenderPass *rpass;
@@ -3113,11 +3274,11 @@ static void addvecmul(float *v1, float *v2, float fac)
v1[2]= v1[2]+fac*v2[2];
}
-static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
+int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
{
- int a, sample, retval = R.osa;
+ int a, sample, osa = (R.osa? R.osa: 1), retval = osa;
- for(a=0; a < R.osa; a++, samp_shr++) {
+ for(a=0; a < osa; a++, samp_shr++) {
ShadeInput *shi= ssamp->shi;
ShadeResult *shr= ssamp->shr;
@@ -3159,7 +3320,7 @@ static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassf
addvecmul(samp_shr->refr, shr->refr, fac);
if(addpassflag & SCE_PASS_RADIO)
- addvecmul(samp_shr->refr, shr->rad, fac);
+ addvecmul(samp_shr->rad, shr->rad, fac);
}
}
}
@@ -3169,7 +3330,7 @@ static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassf
return retval;
}
-static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl)
+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 */
@@ -3178,7 +3339,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl)
fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
if(fp==NULL) return;
- col= rl->acolrect+3;
+ col= rectf+3;
for(a= 4*pa->rectx*pa->recty -4; a>=0; a-=4) {
if(col[a]==0.0f) {
@@ -3222,7 +3383,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* general shader info, passes */
shade_sample_initialize(&ssamp, pa, rl);
addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
- addzbuf= rl->passflag & SCE_PASS_Z;
+ if((rl->layflag & SCE_LAY_STRAND) && R.strandbufs.first)
+ addzbuf= 1; /* strands layer needs the z-buffer */
+ else
+ addzbuf= rl->passflag & SCE_PASS_Z;
if(R.osa)
sampalpha= 1.0f/(float)R.osa;
@@ -3251,7 +3415,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* zero alpha pixels get speed vector max again */
if(addpassflag & SCE_PASS_VECTOR)
if(rl->layflag & SCE_LAY_SOLID)
- reset_sky_speedvectors(pa, rl);
+ reset_sky_speedvectors(pa, rl, rl->acolrect);
/* filtered render, for now we assume only 1 filter size */
if(pa->crop) {