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.
This commit is contained in:
Brecht Van Lommel
2008-01-28 16:54:52 +00:00
parent 703f248ab4
commit f25d2dbb41
9 changed files with 475 additions and 793 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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<<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);
@@ -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)

View File

@@ -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

View File

@@ -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; a<size; a++) {
BLI_freelistN(&buckets->inside[a]);
BLI_freelistN(&buckets->overlap[a]);
}
if(buckets->inside)
MEM_freeN(buckets->inside);
if(buckets->overlap)
MEM_freeN(buckets->overlap);
MEM_freeN(buckets);
}
void project_hoco_to_bucket(RenderBuckets *buckets, float *hoco, float *bucketco)
{
float div;
div= 1.0f/hoco[3];
bucketco[0]= buckets->zmulx*(0.5 + 0.5f*hoco[0]*div) + buckets->zofsx;
bucketco[1]= buckets->zmuly*(0.5 + 0.5f*hoco[1]*div) + buckets->zofsy;
}
typedef struct RenderPrimitiveIterator {
Render *re;
RenderBuckets *buckets;
ListBase *list[6];
int listindex, totlist;
BucketPrims *bpr;
int bprindex;
ObjectInstanceRen *obi;
StrandRen *strand;
int index, tot;
} RenderPrimitiveIterator;
RenderPrimitiveIterator *init_primitive_iterator(Render *re, RenderBuckets *buckets, RenderPart *pa)
{
RenderPrimitiveIterator *iter;
int nr, x, y, width;
iter= MEM_callocN(sizeof(RenderPrimitiveIterator), "RenderPrimitiveIterator");
iter->re= re;
if(buckets) {
iter->buckets= buckets;
nr= BLI_findindex(&re->parts, pa);
width= buckets->x - 1;
x= (nr % width) + 1;
y= (nr / width) + 1;
iter->list[iter->totlist++]= &buckets->all;
iter->list[iter->totlist++]= &buckets->inside[y*buckets->x + x];
iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + x];
iter->list[iter->totlist++]= &buckets->overlap[y*buckets->x + (x-1)];
iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + (x-1)];
iter->list[iter->totlist++]= &buckets->overlap[(y-1)*buckets->x + x];
}
else {
iter->index= 0;
iter->obi= re->instancetable.first;
if(iter->obi)
iter->tot= iter->obi->obr->totstrand;
}
return iter;
}
void *next_primitive_iterator(RenderPrimitiveIterator *iter)
{
if(iter->buckets) {
if(iter->bpr && iter->bprindex >= iter->bpr->totprim) {
iter->bpr= iter->bpr->next;
iter->bprindex= 0;
}
while(iter->bpr == NULL) {
if(iter->listindex == iter->totlist)
return NULL;
iter->bpr= iter->list[iter->listindex++]->first;
iter->bprindex= 0;
}
return iter->bpr->prim[iter->bprindex++];
}
else {
if(!iter->obi)
return NULL;
if(iter->index >= iter->tot) {
while((iter->obi=iter->obi->next) && !iter->obi->obr->totstrand)
iter->obi= iter->obi->next;
if(iter->obi)
iter->tot= iter->obi->obr->totstrand;
else
return NULL;
}
if(iter->index < iter->tot) {
if((iter->index & 255)==0)
iter->strand= iter->obi->obr->strandnodes[iter->index>>8].strand;
else
iter->strand++;
return iter->strand;
}
else
return NULL;
}
}
void free_primitive_iterator(RenderPrimitiveIterator *iter)
{
MEM_freeN(iter);
}
/* *************** */
@@ -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<<spart->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<<spart->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];
#define CHECK_ADD(n) \
if(apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \
{ if(!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; }
#define CHECK_ASSIGN(n) \
if(apn->p[n]==0) \
{apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; }
/* add to pixel list */
if(zverg < bufferz) {
/* 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);
s = fabs(u*spart->s[0] + v*spart->s[1] + (1.0f-u-v)*spart->s[2]);
/* 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);
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);
strand_apply_shaderesult_alpha(spart->ssamp.shr, s);
apnew= addpsAstrand(spart->zspan);
SWAP(APixstrand, *apnew, *apn);
apn->next= apnew;
CHECK_ASSIGN(0);
}
/* 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->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; 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 {
alpha= 0.0f;
if(pa->fullresult.first) {
for(a=0; a<re->osa; 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; a<re->osa; a++) {
add_filt_fmask(1<<a, shr[a].combined, pass, rr->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; a<resultsize; a++) {
spart.result[a].winspeed[0]= PASS_VECTOR_MAX;
spart.result[a].winspeed[1]= PASS_VECTOR_MAX;
spart.result[a].winspeed[2]= PASS_VECTOR_MAX;
spart.result[a].winspeed[3]= PASS_VECTOR_MAX;
}
}
if(spart.addzbuf) {
/* duplicate rectz so we can read from the old buffer, while
* writing new z values */
spart.rectz= MEM_dupallocN(pa->rectz);
spart.outrectz= pa->rectz;
}
shade_sample_initialize(&spart.ssamp1, pa, rl);
shade_sample_initialize(&spart.ssamp2, pa, rl);
shade_sample_initialize(&spart.ssamp, pa, rl);
spart.ssamp1.shi[0].sample= 0;
spart.ssamp2.shi[0].sample= 1;
spart.ssamp1.tot= 1;
spart.ssamp2.tot= 1;
spart.ssamp.tot= 1;
spart.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; a<obr->totstrand; 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; 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 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)
{

View File

@@ -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; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
pass= passrect;
ap= aprect;
apstrand= aprectstrand;
od= offs;
if(R.test_break())
break;
for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, pass+=4, od++) {
for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, apstrand++, pass+=4, od++) {
if(ap->p[0]==0) {
if(ap->p[0]==0 && (!APixbufstrand || apstrand->p[0]==0)) {
if(addpassflag & SCE_PASS_VECTOR)
add_transp_speed(rl, od, NULL, 0.0f, rdrect);
}
@@ -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; b<R.osa; b++)
if(zrow[totface].mask & (1<<b))
totsample++;
}
else
totsample= 1;
zrow[totface].u= apnstrand->u[a]/totsample;
zrow[totface].v= apnstrand->v[a]/totsample;
totface++;
if(totface>=MAX_ZROW) totface= MAX_ZROW-1;
}
}
apnstrand= apnstrand->next;
}
if(totface==2) {
if(zrow[0].z < zrow[1].z) {
SWAP(ZTranspRow, zrow[0], zrow[1]);
@@ -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)