From f25d2dbb411a2eb6095a53893759a3fc29904ffd Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 28 Jan 2008 16:54:52 +0000 Subject: Strands now mix together correctly with ZTransp. They now also store a list of samples per pixel, and then get shaded together with the ztransp samples. This comes with a slight speed hit, but mainly memory might be a concern. However, testing some peach scenes I haven't problems. --- .../blender/render/intern/include/render_types.h | 8 +- source/blender/render/intern/include/rendercore.h | 2 - source/blender/render/intern/include/strand.h | 9 +- source/blender/render/intern/include/zbuf.h | 18 +- source/blender/render/intern/source/envmap.c | 2 - source/blender/render/intern/source/rendercore.c | 73 +- .../blender/render/intern/source/renderdatabase.c | 58 +- source/blender/render/intern/source/strand.c | 945 ++++++--------------- source/blender/render/intern/source/zbuf.c | 157 +++- 9 files changed, 477 insertions(+), 795 deletions(-) (limited to 'source/blender') diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index de5c5485004..3a8a491a852 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -176,7 +176,6 @@ struct Render ListBase lampren; /* storage, for free */ ListBase objecttable; - struct RenderBuckets *strandbuckets; struct ObjectInstanceRen *objectinstance; ListBase instancetable; @@ -334,6 +333,8 @@ typedef struct HaloRen struct Material *mat; } HaloRen; +/* ------------------------------------------------------------------------- */ + typedef struct StrandVert { float co[3]; float strandco; @@ -351,6 +352,11 @@ typedef struct StrandSurface { int totvert, totface; } StrandSurface; +typedef struct StrandBound { + int start, end; + float bbox[2][3]; +} StrandBound; + typedef struct StrandBuffer { struct StrandBuffer *next, *prev; struct StrandVert *vert; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index d569028fc50..4ca644c6381 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -91,8 +91,6 @@ void zbufshadeDA_tile(struct RenderPart *pa); void zbufshade_sss_tile(struct RenderPart *pa); -void addps(struct ListBase *lb, long *rd, int obi, int facenr, int z, unsigned short mask); - int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp); diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h index 8e34fa27342..f001bc42112 100644 --- a/source/blender/render/intern/include/strand.h +++ b/source/blender/render/intern/include/strand.h @@ -88,13 +88,20 @@ typedef struct StrandSegment { int shaded; } StrandSegment; +struct StrandShadeCache; +typedef struct StrandShadeCache StrandShadeCache; + void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint); void render_strand_segment(struct Render *re, float winmat[][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg); -void project_strands(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int do_buckets); struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[][4], int timeoffset); void free_strand_surface(struct Render *re); +struct StrandShadeCache *strand_shade_cache_create(void); +void strand_shade_cache_free(struct StrandShadeCache *cache); +void strand_shade_segment(struct Render *re, struct StrandShadeCache *cache, struct StrandSegment *sseg, struct ShadeSample *ssamp, float t, float s, int addpassflag); +void strand_shade_unref(struct StrandShadeCache *cache, struct StrandVert *svert); + struct RenderBuckets *init_buckets(struct Render *re); void add_buckets_primitive(struct RenderBuckets *buckets, float *min, float *max, void *prim); void free_buckets(struct RenderBuckets *buckets); diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index 8feb18a7ab8..2a16bde829b 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -36,6 +36,8 @@ struct LampRen; struct VlakRen; struct ListBase; struct ZSpan; +struct APixstrand; +struct StrandShadeCache; void fillrect(int *rect, int x, int y, int val); @@ -51,9 +53,9 @@ void zbuffer_shadow(struct Render *re, float winmat[][4], struct LampRen *lar, i void zbuffer_solid(struct RenderPart *pa, struct RenderLayer *rl, void (*fillfunc)(struct RenderPart*, struct ZSpan*, int, void*), void *data); unsigned short *zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass, struct ListBase *psmlist); -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, int)); +int zbuffer_strands_abuf(struct Render *re, struct RenderPart *pa, struct RenderLayer *rl, struct APixstrand *apixbuf, struct ListBase *apsmbase, struct StrandShadeCache *cache); typedef struct APixstr { unsigned short mask[4]; /* jitter mask */ @@ -64,10 +66,20 @@ typedef struct APixstr { struct APixstr *next; } APixstr; +typedef struct APixstrand { + unsigned short mask[4]; /* jitter mask */ + int z[4]; /* distance */ + int p[4]; /* index */ + int obi[4]; /* object instance */ + int seg[4]; /* for strands, segment number */ + float u[4], v[4]; /* for strands, u,v coordinate in segment */ + struct APixstrand *next; +} APixstrand; + typedef struct APixstrMain { struct APixstrMain *next, *prev; - struct APixstr *ps; + void *ps; } APixstrMain; /* span fill in method, is also used to localize data for zbuffering */ @@ -85,11 +97,13 @@ typedef struct ZSpan { int *rectp; /* polygon index buffer */ int *recto; /* object buffer */ APixstr *apixbuf, *curpstr; /* apixbuf for transparent */ + APixstrand *curpstrand; /* same for strands */ struct ListBase *apsmbase; int polygon_offset; /* offset in Z */ float shad_alpha; /* copy from material, used by irregular shadbuf */ int mask, apsmcounter; /* in use by apixbuf */ + int apstrandmcounter; float clipcrop; /* for shadow, was in R global before */ diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 6d93d91ae97..81d5c8ea9ed 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -152,7 +152,6 @@ static Render *envmap_render_copy(Render *re, EnvMap *env) envre->totlamp= re->totlamp; envre->lights= re->lights; envre->objecttable= re->objecttable; - envre->strandbuckets= re->strandbuckets; envre->customdata_names= re->customdata_names; envre->raytree= re->raytree; envre->totinstance= re->totinstance; @@ -173,7 +172,6 @@ static void envmap_free_render_copy(Render *envre) envre->totinstance= 0; envre->lights.first= envre->lights.last= NULL; envre->objecttable.first= envre->objecttable.last= NULL; - envre->strandbuckets= NULL; envre->customdata_names.first= envre->customdata_names.last= NULL; envre->raytree= NULL; envre->instancetable.first= envre->instancetable.last= NULL; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index dd5b96a50ca..375d8a23a2e 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -684,7 +684,7 @@ static void freeps(ListBase *lb) lb->first= lb->last= NULL; } -void addps(ListBase *lb, long *rd, int obi, int facenr, int z, unsigned short mask) +static void addps(ListBase *lb, long *rd, int obi, int facenr, int z, unsigned short mask) { PixStrMain *psm; PixStr *ps, *last= NULL; @@ -969,8 +969,8 @@ void zbufshadeDA_tile(RenderPart *pa) halo_tile(pa, rl->rectf, rl->lay); /* transp layer */ - if(R.flag & R_ZTRA) { - if(rl->layflag & SCE_LAY_ZTRA) { + if(R.flag & R_ZTRA || R.totstrand) { + if(rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { if(pa->fullresult.first) { zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist); } @@ -1015,51 +1015,6 @@ void zbufshadeDA_tile(RenderPart *pa) } } - /* strand rendering */ - if((rl->layflag & SCE_LAY_STRAND) && R.totstrand) { - if(pa->fullresult.first) { - zbuffer_strands_shade(&R, pa, rl, rl->rectf); - } - else { - 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<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); @@ -1192,8 +1147,8 @@ void zbufshade_tile(RenderPart *pa) if(rl->layflag & SCE_LAY_HALO) halo_tile(pa, rl->rectf, rl->lay); - if(R.flag & R_ZTRA) { - if(rl->layflag & SCE_LAY_ZTRA) { + if(R.flag & R_ZTRA || R.totstrand) { + if(rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { float *fcol, *acol; int x; @@ -1211,24 +1166,6 @@ void zbufshade_tile(RenderPart *pa) } } } - - /* strand rendering */ - if((rl->layflag & SCE_LAY_STRAND) && R.totstrand) { - float *fcol, *scol; - int x; - - /* allocate, but not free here, for asynchronous display of this rect in main thread */ - rl->scolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "strand layer"); - - /* swap for live updates */ - SWAP(float*, rl->scolrect, rl->rectf); - zbuffer_strands_shade(&R, pa, rl, rl->rectf); - SWAP(float*, rl->scolrect, rl->rectf); - - fcol= rl->rectf; scol= rl->scolrect; - for(x=pa->rectx*pa->recty; x>0; x--, scol+=4, fcol+=4) - addAlphaOverFloat(fcol, scol); - } /* sky before edge */ if(rl->layflag & SCE_LAY_SKY) diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 27daad9dc26..9495360f089 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -868,11 +868,6 @@ void free_renderdata_tables(Render *re) re->sortedhalos= NULL; } - if(re->strandbuckets) { - free_buckets(re->strandbuckets); - re->strandbuckets= NULL; - } - BLI_freelistN(&re->customdata_names); BLI_freelistN(&re->objecttable); BLI_freelistN(&re->instancetable); @@ -1290,8 +1285,6 @@ void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], } } - - project_strands(re, projectfunc, do_pano, do_buckets); } /* ------------------------------------------------------------------------- */ @@ -1349,3 +1342,54 @@ void RE_makeRenderInstances(Render *re) re->instancetable= newlist; } +#if 0 +int clip_render_object(ObjectInstanceRen *obi, float *bounds, float winmat[][4]) +{ + float mat[4][4], vec[4], max, min, (*boundbox)[3]; + int a, fl, flag= -1; + + boundbox= obi->obr->boundbox; + Mat4CpyMat4(mat, winmat); + + for(a=0; a<8; a++) { + vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0]; + vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1]; + vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2]; + vec[3]= 1.0; + Mat4MulVec4fl(mat, vec); + + fl= 0; + if(bounds) { + if(vec[0] > bounds[1]*vec[3]) fl |= 1; + if(vec[0]< bounds[0]*vec[3]) fl |= 2; + if(vec[1] > bounds[3]*vec[3]) fl |= 4; + if(vec[1]< bounds[2]*vec[3]) fl |= 8; + } + else { + if(vec[0] < -vec[3]) fl |= 1; + if(vec[0] > vec[3]) fl |= 2; + if(vec[1] < -vec[3]) fl |= 4; + if(vec[1] > vec[3]) fl |= 8; + } + if(vec[2] < -vec[3]) fl |= 16; + if(vec[2] > vec[3]) fl |= 32; + +#if 0 + max= vec[3]; + min= -vec[3]; + + wco= ho[3]; + if(vec[0] < min) fl |= 1; + if(vec[0] > max) fl |= 2; + if(vec[1] < min) fl |= 4; + if(vec[1] > max) fl |= 8; +#endif + + flag &= fl; + if(flag==0) return 0; + } + + return flag; +} +#endif + diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index b1cba27ba9b..91b3dfbe621 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -57,248 +57,9 @@ #include "zbuf.h" /* to be removed */ -void merge_transp_passes(RenderLayer *rl, ShadeResult *shr); -void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha); void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco); void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) ); void zbufsinglewire(ZSpan *zspan, int obi, 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; ainside[a]); - BLI_freelistN(&buckets->overlap[a]); - } - - if(buckets->inside) - MEM_freeN(buckets->inside); - if(buckets->overlap) - MEM_freeN(buckets->overlap); - - MEM_freeN(buckets); -} - -void project_hoco_to_bucket(RenderBuckets *buckets, float *hoco, float *bucketco) -{ - float div; - - div= 1.0f/hoco[3]; - bucketco[0]= buckets->zmulx*(0.5 + 0.5f*hoco[0]*div) + buckets->zofsx; - bucketco[1]= buckets->zmuly*(0.5 + 0.5f*hoco[1]*div) + buckets->zofsy; -} - -typedef struct RenderPrimitiveIterator { - Render *re; - RenderBuckets *buckets; - ListBase *list[6]; - int listindex, totlist; - BucketPrims *bpr; - int bprindex; - - ObjectInstanceRen *obi; - StrandRen *strand; - int index, tot; -} RenderPrimitiveIterator; - -RenderPrimitiveIterator *init_primitive_iterator(Render *re, RenderBuckets *buckets, RenderPart *pa) -{ - RenderPrimitiveIterator *iter; - int nr, x, y, width; - - iter= MEM_callocN(sizeof(RenderPrimitiveIterator), "RenderPrimitiveIterator"); - iter->re= re; - - if(buckets) { - iter->buckets= buckets; - - nr= BLI_findindex(&re->parts, pa); - width= buckets->x - 1; - x= (nr % width) + 1; - y= (nr / width) + 1; - - iter->list[iter->totlist++]= &buckets->all; - iter->list[iter->totlist++]= &buckets->inside[y*buckets->x + x]; - iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + x]; - iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + (x-1)]; - iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + (x-1)]; - iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + x]; - } - else { - iter->index= 0; - iter->obi= re->instancetable.first; - if(iter->obi) - iter->tot= iter->obi->obr->totstrand; - } - - return iter; -} - -void *next_primitive_iterator(RenderPrimitiveIterator *iter) -{ - if(iter->buckets) { - if(iter->bpr && iter->bprindex >= iter->bpr->totprim) { - iter->bpr= iter->bpr->next; - iter->bprindex= 0; - } - - while(iter->bpr == NULL) { - if(iter->listindex == iter->totlist) - return NULL; - - iter->bpr= iter->list[iter->listindex++]->first; - iter->bprindex= 0; - } - - return iter->bpr->prim[iter->bprindex++]; - } - else { - if(!iter->obi) - return NULL; - - if(iter->index >= iter->tot) { - while((iter->obi=iter->obi->next) && !iter->obi->obr->totstrand) - iter->obi= iter->obi->next; - - if(iter->obi) - iter->tot= iter->obi->obr->totstrand; - else - return NULL; - } - - if(iter->index < iter->tot) { - if((iter->index & 255)==0) - iter->strand= iter->obi->obr->strandnodes[iter->index>>8].strand; - else - iter->strand++; - - return iter->strand; - } - else - return NULL; - } -} - -void free_primitive_iterator(RenderPrimitiveIterator *iter) -{ - MEM_freeN(iter); -} /* *************** */ @@ -422,45 +183,6 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) /* *************** */ -typedef struct StrandPart { - Render *re; - ZSpan *zspan; - - RenderLayer *rl; - ShadeResult *result; - float *pass; - int *rectz, *outrectz; - long *rectdaps; - unsigned short *mask; - int rectx, recty; - int addpassflag, addzbuf, sample; - - StrandSegment *segment; - GHash *hash; - StrandPoint point1, point2; - ShadeSample ssamp1, ssamp2, ssamp; - float t[3], s[3]; -} StrandPart; - -typedef struct StrandSortSegment { - struct StrandSortSegment *next; - int obi, strand, segment; - float z; -} StrandSortSegment; - -static int compare_strand_segment(const void *poin1, const void *poin2) -{ - 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_vec1(float *v1, float *v2, float t, float negt, float *v) { v[0]= negt*v1[0] + t*v2[0]; @@ -481,7 +203,7 @@ static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v v[3]= negt*v1[3] + t*v2[3]; } -static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag) +void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag) { float negt= 1.0f - t; @@ -517,20 +239,7 @@ static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float } } -static void add_strand_obindex(RenderLayer *rl, int offset, ObjectRen *obr) -{ - RenderPass *rpass; - - for(rpass= rl->passes.first; rpass; rpass= rpass->next) { - if(rpass->passtype == SCE_PASS_INDEXOB) { - float *fp= rpass->rect + offset; - *fp= (float)obr->ob->index; - break; - } - } -} - -static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) +void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) { if(alpha < 1.0f) { shr->combined[0] *= alpha; @@ -547,6 +256,191 @@ static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) } } +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; + if(sseg->buffer->ma->mode & MA_TANGENT_STR) + vlr.flag |= R_TANGENT; + + shi->vlr= &vlr; + shi->strand= sseg->strand; + shi->obi= sseg->obi; + shi->obr= sseg->obi->obr; + + /* cache for shadow */ + shi->samplenr= ssamp->samplenr++; + + shade_input_set_strand(shi, sseg->strand, spoint); + shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); + + /* init material vars */ + // note, keep this synced with render_types.h + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); + shi->har= shi->mat->har; + + /* shade */ + shade_samples_do_AO(ssamp); + shade_input_do_shade(shi, shr); + + /* apply simplification */ + strand_apply_shaderesult_alpha(shr, spoint->alpha); + + /* include lamphalos for strand, since halo layer was added already */ + if(re->flag & R_LAMPHALO) + if(shi->layflag & SCE_LAY_HALO) + renderspothalo(shi, shr->combined, shr->combined[3]); + + shi->strand= NULL; +} + +/* *************** */ + +struct StrandShadeCache { + GHash *resulthash; + GHash *refcounthash; + MemArena *memarena; +}; + +StrandShadeCache *strand_shade_cache_create() +{ + StrandShadeCache *cache; + + cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache"); + cache->resulthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + cache->refcounthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + + return cache; +} + +void strand_shade_cache_free(StrandShadeCache *cache) +{ + BLI_ghash_free(cache->refcounthash, NULL, NULL); + BLI_ghash_free(cache->resulthash, NULL, (GHashValFreeFP)MEM_freeN); + BLI_memarena_free(cache->memarena); + MEM_freeN(cache); +} + +static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert) +{ + ShadeResult *hashshr; + StrandPoint p; + int *refcount; + + hashshr= BLI_ghash_lookup(cache->resulthash, svert); + refcount= BLI_ghash_lookup(cache->refcounthash, svert); + + if(!hashshr) { + /* not shaded yet, shade and insert into hash */ + p.t= (sseg->v[1] == svert)? 0.0f: 1.0f; + strand_eval_point(sseg, &p); + strand_shade_point(re, ssamp, sseg, &p); + + hashshr= MEM_callocN(sizeof(ShadeResult), "HashShadeResult"); + *hashshr= ssamp->shr[0]; + BLI_ghash_insert(cache->resulthash, svert, hashshr); + } + else + /* already shaded, just copy previous result from hash */ + ssamp->shr[0]= *hashshr; + + /* lower reference count and remove if not needed anymore by any samples */ + (*refcount)--; + if(*refcount == 0) { + BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN); + BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL); + } +} + +void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag) +{ + ShadeResult shr1, shr2; + + /* get shading for two endpoints and interpolate */ + strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]); + shr1= ssamp->shr[0]; + strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]); + shr2= ssamp->shr[0]; + + interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag); + + /* apply alpha along width */ + if(sseg->buffer->widthfade != 0.0f) { + s = 1.0f - pow(fabs(s), sseg->buffer->widthfade); + + strand_apply_shaderesult_alpha(ssamp->shr, s); + } +} + +void strand_shade_unref(StrandShadeCache *cache, StrandVert *svert) +{ + int *refcount; + + /* lower reference count and remove if not needed anymore by any samples */ + refcount= BLI_ghash_lookup(cache->refcounthash, svert); + + (*refcount)--; + if(*refcount == 0) { + BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN); + BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL); + } +} + +static void strand_shade_refcount(StrandShadeCache *cache, StrandVert *svert) +{ + int *refcount= BLI_ghash_lookup(cache->refcounthash, svert); + + if(!refcount) { + refcount= BLI_memarena_alloc(cache->memarena, sizeof(int)); + *refcount= 1; + BLI_ghash_insert(cache->refcounthash, svert, refcount); + } + else + (*refcount)++; +} + +/* *************** */ + +typedef struct StrandPart { + Render *re; + ZSpan *zspan; + + APixstrand *apixbuf; + int *rectz; + long *rectdaps; + int rectx, recty; + int sample; + + StrandSegment *segment; + float t[3], s[3]; + + StrandShadeCache *cache; +} StrandPart; + +typedef struct StrandSortSegment { + struct StrandSortSegment *next; + int obi, strand, segment; + float z; +} StrandSortSegment; + +static int compare_strand_segment(const void *poin1, const void *poin2) +{ + const StrandSortSegment *seg1= (const StrandSortSegment*)poin1; + const StrandSortSegment *seg2= (const StrandSortSegment*)poin2; + + if(seg1->z > seg2->z) + return -1; + else if(seg1->z == seg2->z) + return 0; + else + return 1; +} + static void do_strand_point_project(float winmat[][4], ZSpan *zspan, float *co, float *hoco, float *zco) { projectvert(co, winmat, hoco); @@ -564,69 +458,59 @@ static void strand_project_point(float winmat[][4], float winx, float winy, Stra spoint->y= spoint->hoco[1]*div*winy*0.5f; } -static 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) +static APixstrand *addpsmainAstrand(ListBase *lb) { - ShadeResult *hashshr; + APixstrMain *psm; - if(lookup) { - hashshr= BLI_ghash_lookup(spart->hash, svert); + psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA"); + BLI_addtail(lb, psm); + psm->ps= MEM_callocN(4096*sizeof(APixstrand),"pixstr"); - 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); + return psm->ps; } -static void strand_shade_segment(StrandPart *spart) +static APixstrand *addpsAstrand(ZSpan *zspan) { - 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; + /* make new PS */ + if(zspan->apstrandmcounter==0) { + zspan->curpstrand= addpsmainAstrand(zspan->apsmbase); + zspan->apstrandmcounter= 4095; + } + else { + zspan->curpstrand++; + zspan->apstrandmcounter--; } + return zspan->curpstrand; } -static void do_strand_blend(void *handle, int x, int y, float u, float v, float z) +static void do_strand_fillac(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, s; - int offset, zverg, bufferz; + StrandShadeCache *cache= spart->cache; + StrandSegment *sseg= spart->segment; + APixstrand *apn, *apnew; + float t, s; + int offset, mask, obi, strnr, seg, zverg, bufferz; - /* check again solid z-buffer */ offset = y*spart->rectx + x; + obi= sseg->obi - spart->re->objectinstance; + strnr= sseg->strand->index + 1; + seg= sseg->v[1] - sseg->strand->vert; + mask= (1<sample); + + /* check against solid z-buffer */ zverg= (int)z; if(spart->rectdaps) { /* find the z of the sample */ PixStr *ps; long *rd= spart->rectdaps + offset; - int sample= (1<sample); bufferz= 0x7FFFFFFF; if(*rd) { for(ps= (PixStr *)(*rd); ps; ps= ps->next) { - if(sample & ps->mask) { + if(mask & ps->mask) { bufferz= ps->z; break; } @@ -636,48 +520,37 @@ static void do_strand_blend(void *handle, int x, int y, float u, float v, float else bufferz= spart->rectz[offset]; - if(zverg < bufferz) { - /* 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); +#define CHECK_ADD(n) \ + if(apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \ + { if(!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } +#define CHECK_ASSIGN(n) \ + if(apn->p[n]==0) \ + {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } - /* interpolate shading from two control points */ + /* add to pixel list */ + if(zverg < bufferz) { 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); - - /* alpha along width */ - if(buffer->widthfade != 0.0f) { - s = fabs(u*spart->s[0] + v*spart->s[1] + (1.0f-u-v)*spart->s[2]); - s = 1.0f - pow(s, buffer->widthfade); - - strand_apply_shaderesult_alpha(spart->ssamp.shr, s); - } - - /* add in shaderesult array for part */ - spart->ssamp.shi[0].mask= (1<sample); - addtosamp_shr(shr, &spart->ssamp, spart->addpassflag); - spart->mask[offset] |= (1<sample); - -#if 0 - /* fill in pass for preview */ - if(spart->sample == 0) { - pass= spart->pass + offset*4; - QUATCOPY(pass, shr->combined); + s = fabs(u*spart->s[0] + v*spart->s[1] + (1.0f-u-v)*spart->s[2]); + + apn= spart->apixbuf + offset; + while(apn) { + CHECK_ADD(0); + CHECK_ADD(1); + CHECK_ADD(2); + CHECK_ADD(3); + CHECK_ASSIGN(0); + CHECK_ASSIGN(1); + CHECK_ASSIGN(2); + CHECK_ASSIGN(3); + + apnew= addpsAstrand(spart->zspan); + SWAP(APixstrand, *apnew, *apn); + apn->next= apnew; + CHECK_ASSIGN(0); } -#endif - if(spart->addpassflag & SCE_PASS_INDEXOB) - add_strand_obindex(spart->rl, offset, buffer->obr); + strand_shade_refcount(cache, sseg->v[1]); + strand_shade_refcount(cache, sseg->v[2]); } } @@ -701,46 +574,6 @@ static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, floa return clipflag; } -static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint) -{ - ShadeInput *shi= ssamp->shi; - ShadeResult *shr= ssamp->shr; - VlakRen vlr; - - memset(&vlr, 0, sizeof(vlr)); - vlr.flag= R_SMOOTH; - if(sseg->buffer->ma->mode & MA_TANGENT_STR) - vlr.flag |= R_TANGENT; - - shi->vlr= &vlr; - shi->strand= sseg->strand; - shi->obi= sseg->obi; - shi->obr= sseg->obi->obr; - - /* cache for shadow */ - shi->samplenr++; - - shade_input_set_strand(shi, sseg->strand, spoint); - shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); - - /* init material vars */ - // note, keep this synced with render_types.h - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; - - /* shade */ - shade_samples_do_AO(ssamp); - shade_input_do_shade(shi, shr); - - /* apply simplification */ - strand_apply_shaderesult_alpha(shr, spoint->alpha); - - /* include lamphalos for strand, since halo layer was added already */ - if(re->flag & R_LAMPHALO) - if(shi->layflag & SCE_LAY_HALO) - renderspothalo(shi, shr->combined, shr->combined[3]); -} - 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; @@ -777,14 +610,14 @@ static void do_scanconvert_strand(Render *re, StrandPart *spart, ZSpan *zspan, f spart->s[1]= 1.0f; spart->t[2]= t; spart->s[2]= 1.0f; - zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_blend); + zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac); spart->t[0]= t-dt; spart->s[0]= -1.0f; spart->t[1]= t; spart->s[1]= 1.0f; spart->t[2]= t; spart->s[2]= -1.0f; - zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_blend); + zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac); } static void strand_render(Render *re, StrandSegment *sseg, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2) @@ -909,110 +742,9 @@ void render_strand_segment(Render *re, float winmat[][4], StrandPart *spart, ZSp strand_render(re, sseg, winmat, spart, zspan, totzspan, 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; - RenderLayer *rl_pp[RE_MAX_OSA]; - float *passrect= pass, alpha, sampalpha; - long *rdrect; - int osa, x, y, a, crop= 0, offs=0, od; - - osa= (re->osa? re->osa: 1); - sampalpha= 1.0f/osa; - - /* only used for multisample buffers */ - get_sample_layers(pa, rl, rl_pp); - - /* 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?rl->scolrect:rl->rectf); /* scolrect==NULL for multisample */ - - /* 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; ydisprect.ymax-crop; y++, rr->renrect.ymax++) { - pass= passrect; - shr= shrrect; - od= offs; - - for(x=pa->disprect.xmin+crop; xdisprect.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 { - alpha= 0.0f; - - if(pa->fullresult.first) { - for(a=0; aosa; a++) { - alpha= shr[a].combined[3]; - if(alpha!=0.0f) { - RenderLayer *rl= rl_pp[a]; - - addAlphaOverFloat(rl->rectf + 4*od, shr[a].combined); - - add_transp_passes(rl, od, shr, alpha); - if(spart->addpassflag & SCE_PASS_VECTOR) - add_transp_speed(rl, od, shr[a].winspeed, alpha, rdrect); - } - } - - } - else { - - if(re->osa == 0) { - addAlphaUnderFloat(pass, shr->combined); - } - else { - /* note; cannot use pass[3] for alpha due to filtermask */ - for(a=0; aosa; a++) { - add_filt_fmask(1<rectx); - alpha += shr[a].combined[3]; - } - } - - if(spart->addpassflag) { - alpha *= sampalpha; - - /* merge all in one, and then add */ - merge_transp_passes(rl, shr); - add_transp_passes(rl, od, shr, alpha); - - if(spart->addpassflag & SCE_PASS_VECTOR) - add_transp_speed(rl, od, shr->winspeed, alpha, 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) +int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand *apixbuf, ListBase *apsmbase, StrandShadeCache *cache) { - //struct RenderPrimitiveIterator *iter; ObjectRen *obr; ObjectInstanceRen *obi; ZSpan zspan; @@ -1023,56 +755,24 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; MemArena *memarena; float z[4], bounds[4], winmat[4][4]; - int a, b, i, resultsize, totsegment, clip[4]; + int a, b, i, totsegment, clip[4]; if(re->test_break()) - return NULL; + return 0; if(re->totstrand == 0) - return NULL; + return 0; /* setup StrandPart */ memset(&spart, 0, sizeof(spart)); spart.re= re; - spart.rl= rl; - spart.pass= pass; spart.rectx= pa->rectx; spart.recty= pa->recty; - spart.rectz= pa->rectz; + spart.apixbuf= apixbuf; + spart.zspan= &zspan; spart.rectdaps= pa->rectdaps; - 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; arectz); - spart.outrectz= pa->rectz; - } - - shade_sample_initialize(&spart.ssamp1, pa, rl); - shade_sample_initialize(&spart.ssamp2, pa, rl); - shade_sample_initialize(&spart.ssamp, pa, rl); - spart.ssamp1.shi[0].sample= 0; - spart.ssamp2.shi[0].sample= 1; - spart.ssamp1.tot= 1; - spart.ssamp2.tot= 1; - spart.ssamp.tot= 1; + spart.rectz= pa->rectz; + spart.cache= cache; zbuf_alloc_span(&zspan, pa->rectx, pa->recty, re->clipcrop); @@ -1087,21 +787,19 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r zspan.zofsx -= 0.5f; zspan.zofsy -= 0.5f; + zspan.apsmbase= apsmbase; + /* clipping setup */ bounds[0]= (2*pa->disprect.xmin - re->winx-1)/(float)re->winx; bounds[1]= (2*pa->disprect.xmax - re->winx+1)/(float)re->winx; bounds[2]= (2*pa->disprect.ymin - re->winy-1)/(float)re->winy; bounds[3]= (2*pa->disprect.ymax - re->winy+1)/(float)re->winy; - /* sort segments */ - //iter= init_primitive_iterator(re, re->strandbuckets, pa); - memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); firstseg= NULL; sortseg= sortsegments; totsegment= 0; - //while((strand = next_primitive_iterator(iter))) { for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { obr= obi->obr; @@ -1120,11 +818,6 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r if(!(strand->buffer->lay & rl->lay)) continue; -#if 0 - if(strand->clip) - continue; -#endif - svert= strand->vert; /* keep clipping and z depth for 4 control points */ @@ -1163,10 +856,6 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r } } -#if 0 - free_primitive_iterator(iter); -#endif - if(!re->test_break()) { /* convert list to array and sort */ sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment"); @@ -1177,8 +866,6 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r BLI_memarena_free(memarena); - spart.hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - if(!re->test_break()) { /* render segments in sorted order */ sortseg= sortsegments; @@ -1209,133 +896,15 @@ unsigned short *zbuffer_strands_shade(Render *re, RenderPart *pa, RenderLayer *r } } - // 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)) || (pa->fullresult.first)) { - MEM_freeN(spart.mask); - spart.mask= NULL; - } - - return spart.mask; + return totsegment; } -void project_strands(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, int do_buckets) -{ -#if 0 - ObjectRen *obr; - StrandRen *strand = NULL; - StrandVert *svert; - float hoco[4], min[2], max[2], bucketco[2], vec[3]; - int a, b; - /* float bmin[3], bmax[3], bpad[3], padding[2]; */ - - if(re->strandbuckets) { - free_buckets(re->strandbuckets); - re->strandbuckets= NULL; - } - - if(re->totstrand == 0) - return; - - if(do_buckets) - re->strandbuckets= init_buckets(re); - - /* calculate view coordinates (and zbuffer value) */ - for(obr=re->objecttable.first; obr; obr=obr->next) { - for(a=0; atotstrand; a++) { - if((a & 255)==0) strand= obr->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; btotvert; 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; btotvert; 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 0 - if(do_buckets) { - project_hoco_to_bucket(re->strandbuckets, hoco, bucketco); - DO_MINMAX2(bucketco, min, max); - } -#endif - } - -#if 0 - if(do_buckets) { - if(strand->buffer->flag & R_STRAND_BSPLINE) { - min[0] -= width; - min[1] -= width; - max[0] += width; - max[1] += width; - } - else { - /* catmull-rom stays within 1.2f bounds in object space, - * is this still true after projection? */ - min[0] -= width + (max[0]-min[0])*0.2f; - min[1] -= width + (max[1]-min[1])*0.2f; - max[0] += width + (max[0]-min[0])*0.2f; - max[1] += width + (max[1]-min[1])*0.2f; - } - - add_buckets_primitive(re->strandbuckets, min, max, strand); - } -#endif - } - } -#endif -} +/* *************** */ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[][4], int timeoffset) { diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 8aa2e06714c..3acce279836 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -3438,12 +3438,11 @@ void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, lo } } -static void add_transp_obindex(RenderLayer *rl, int offset, int obi, int facenr) +static void add_transp_obindex(RenderLayer *rl, int offset, int obi) { ObjectRen *obr= R.objectinstance[obi].obr; - VlakRen *vlr= RE_findOrAddVlak(obr, (facenr-1) & RE_QUAD_MASK); - if(vlr && obr->ob) { + if(obr->ob) { RenderPass *rpass; for(rpass= rl->passes.first; rpass; rpass= rpass->next) { @@ -3600,12 +3599,13 @@ void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alph } } - typedef struct ZTranspRow { int obi; int z; int p; int mask; + int segment; + float u, v; } ZTranspRow; static int vergzvlak(const void *a1, const void *a2) @@ -3617,6 +3617,56 @@ static int vergzvlak(const void *a1, const void *a2) return 0; } +static void shade_strand_samples(StrandShadeCache *cache, ShadeSample *ssamp, int x, int y, ZTranspRow *row, int addpassflag) +{ + StrandSegment sseg; + StrandVert *svert; + ObjectInstanceRen *obi; + ObjectRen *obr; + + obi= R.objectinstance + row->obi; + obr= obi->obr; + + sseg.obi= obi; + sseg.strand= RE_findOrAddStrand(obr, row->p-1); + sseg.buffer= sseg.strand->buffer; + + svert= sseg.strand->vert + row->segment; + sseg.v[0]= (row->segment > 0)? (svert-1): svert; + sseg.v[1]= svert; + sseg.v[2]= svert+1; + sseg.v[3]= (row->segment < sseg.strand->totvert-2)? svert+2: svert+1; + + strand_shade_segment(&R, cache, &sseg, ssamp, row->v, row->u, addpassflag); + ssamp->shi[0].mask= row->mask; + ssamp->tot= 1; +} + +static void unref_strand_samples(StrandShadeCache *cache, ZTranspRow *row, int totface) +{ + StrandVert *svert; + ObjectInstanceRen *obi; + ObjectRen *obr; + StrandRen *strand; + + /* remove references to samples that are not being rendered, but we still + * need to remove them so that the reference count of strand vertex shade + * samples correctly drops to zero */ + while(totface > 0) { + totface--; + + if(row[totface].segment != -1) { + obi= R.objectinstance + row[totface].obi; + obr= obi->obr; + strand= RE_findOrAddStrand(obr, row[totface].p-1); + svert= strand->vert + row[totface].segment; + + strand_shade_unref(cache, svert); + strand_shade_unref(cache, svert+1); + } + } +} + static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int obi, int facenr, int curmask) { ShadeInput *shi= ssamp->shi; @@ -3674,8 +3724,13 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int } } -static int shade_tra_samples(ShadeSample *ssamp, int x, int y, ZTranspRow *row) +static int shade_tra_samples(ShadeSample *ssamp, StrandShadeCache *cache, int x, int y, ZTranspRow *row, int addpassflag) { + if(row->segment != -1) { + shade_strand_samples(cache, ssamp, x, y, row, addpassflag); + return 1; + } + shade_tra_samples_fill(ssamp, x, y, row->z, row->obi, row->p, row->mask); if(ssamp->tot) { @@ -3800,16 +3855,19 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas RenderResult *rr= pa->result; ShadeSample ssamp; APixstr *APixbuf; /* Zbuffer: linked list of face samples */ + APixstrand *APixbufstrand = NULL; APixstr *ap, *aprect, *apn; + APixstrand *apstrand, *aprectstrand, *apnstrand; ListBase apsmbase={NULL, NULL}; ShadeResult samp_shr[16]; /* MAX_OSA */ ZTranspRow zrow[MAX_ZROW]; + StrandShadeCache *sscache= NULL; float sampalpha, *passrect= pass; long *rdrect; - int x, y, crop=0, a, totface; + int x, y, crop=0, a, b, totface, totsample, doztra; int addpassflag, offs= 0, od, addzbuf; unsigned short *ztramask= NULL; - + /* looks nicer for calling code */ if(R.test_break()) return NULL; @@ -3821,14 +3879,15 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas } APixbuf= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf"); + if(R.totstrand && (rl->layflag & SCE_LAY_STRAND)) { + APixbufstrand= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstrand), "APixbufstrand"); + sscache= strand_shade_cache_create(); + } /* general shader info, passes */ shade_sample_initialize(&ssamp, pa, rl); addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED); - if((rl->layflag & SCE_LAY_STRAND) && R.totstrand) - addzbuf= 1; /* strands layer needs the z-buffer */ - else - addzbuf= rl->passflag & SCE_PASS_Z; + addzbuf= rl->passflag & SCE_PASS_Z; if(R.osa) sampalpha= 1.0f/(float)R.osa; @@ -3836,14 +3895,25 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas sampalpha= 1.0f; /* fill the Apixbuf */ - if(0 == zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay)) { + doztra= 0; + if(rl->layflag & SCE_LAY_ZTRA) + doztra+= zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay); + if((rl->layflag & SCE_LAY_STRAND) && APixbufstrand) + doztra+= zbuffer_strands_abuf(&R, pa, rl, APixbufstrand, &apsmbase, sscache); + + if(doztra == 0) { /* nothing filled in */ MEM_freeN(APixbuf); + if(APixbufstrand) + MEM_freeN(APixbufstrand); + if(sscache) + strand_shade_cache_free(sscache); freepsA(&apsmbase); return NULL; } aprect= APixbuf; + aprectstrand= APixbufstrand; rdrect= pa->rectdaps; /* irregular shadowb buffer creation */ @@ -3865,6 +3935,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas offs= pa->rectx + 1; passrect+= 4*offs; aprect+= offs; + aprectstrand+= offs; } /* init scanline updates */ @@ -3876,14 +3947,15 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas for(y=pa->disprect.ymin+crop; ydisprect.ymax-crop; y++, rr->renrect.ymax++) { pass= passrect; ap= aprect; + apstrand= aprectstrand; od= offs; if(R.test_break()) break; - for(x=pa->disprect.xmin+crop; xdisprect.xmax-crop; x++, ap++, pass+=4, od++) { + for(x=pa->disprect.xmin+crop; xdisprect.xmax-crop; x++, ap++, apstrand++, pass+=4, od++) { - if(ap->p[0]==0) { + if(ap->p[0]==0 && (!APixbufstrand || apstrand->p[0]==0)) { if(addpassflag & SCE_PASS_VECTOR) add_transp_speed(rl, od, NULL, 0.0f, rdrect); } @@ -3898,6 +3970,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas zrow[totface].z= apn->z[a]; zrow[totface].p= apn->p[a]; zrow[totface].mask= apn->mask[a]; + zrow[totface].segment= -1; totface++; if(totface>=MAX_ZROW) totface= MAX_ZROW-1; } @@ -3905,7 +3978,35 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas } apn= apn->next; } - + + apnstrand= (APixbufstrand)? apstrand: NULL; + while(apnstrand) { + for(a=0; a<4; a++) { + if(apnstrand->p[a]) { + zrow[totface].obi= apnstrand->obi[a]; + zrow[totface].z= apnstrand->z[a]; + zrow[totface].p= apnstrand->p[a]; + zrow[totface].mask= apnstrand->mask[a]; + zrow[totface].segment= apnstrand->seg[a]; + + if(R.osa) { + totsample= 0; + for(b=0; bu[a]/totsample; + zrow[totface].v= apnstrand->v[a]/totsample; + totface++; + if(totface>=MAX_ZROW) totface= MAX_ZROW-1; + } + } + apnstrand= apnstrand->next; + } + if(totface==2) { if(zrow[0].z < zrow[1].z) { SWAP(ZTranspRow, zrow[0], zrow[1]); @@ -3922,19 +4023,22 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas pa->rectz[od]= zrow[totface-1].z; if(addpassflag & SCE_PASS_INDEXOB) - add_transp_obindex(rl, od, zrow[totface-1].obi, zrow[totface-1].p); - + add_transp_obindex(rl, od, zrow[totface-1].obi); if(R.osa==0) { while(totface>0) { totface--; - if(shade_tra_samples(&ssamp, x, y, &zrow[totface])) { + if(shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) { if(addpassflag) add_transp_passes(rl, od, ssamp.shr, (1.0f-pass[3])*ssamp.shr[0].combined[3]); addAlphaUnderFloat(pass, ssamp.shr[0].combined); - if(pass[3]>=0.999) break; + if(pass[3]>=0.999) { + if(sscache) + unref_strand_samples(sscache, zrow, totface); + break; + } } } if(addpassflag & SCE_PASS_VECTOR) @@ -3954,16 +4058,16 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas while(totface>0) { totface--; - if(shade_tra_samples(&ssamp, x, y, &zrow[totface])) { + if(shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) { filled= addtosamp_shr(samp_shr, &ssamp, addpassflag); if(ztramask) *sp |= zrow[totface].mask; - if(filled==0) + if(filled==0) { + if(sscache) + unref_strand_samples(sscache, zrow, totface); break; - - if(R.totstrand) - addps(psmlist, pa->rectdaps+od, zrow[totface].obi, zrow[totface].p, zrow[totface].z, zrow[totface].mask); + } } } @@ -4006,6 +4110,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas } aprect+= pa->rectx; + aprectstrand+= pa->rectx; passrect+= 4*pa->rectx; offs+= pa->rectx; } @@ -4014,6 +4119,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas rr->renlay= NULL; MEM_freeN(APixbuf); + if(APixbufstrand) + MEM_freeN(APixbufstrand); + if(sscache) + strand_shade_cache_free(sscache); freepsA(&apsmbase); if(R.r.mode & R_SHADOW) -- cgit v1.2.3