diff options
Diffstat (limited to 'source/blender/render/intern/source/strand.c')
-rw-r--r-- | source/blender/render/intern/source/strand.c | 1069 |
1 files changed, 0 insertions, 1069 deletions
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c deleted file mode 100644 index 5fde688481a..00000000000 --- a/source/blender/render/intern/source/strand.c +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: Brecht Van Lommel. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/render/intern/source/strand.c - * \ingroup render - */ - - -#include <math.h> -#include <string.h> -#include <stdlib.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_key_types.h" -#include "DNA_material_types.h" -#include "DNA_meshdata_types.h" - -#include "BLI_math.h" -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" -#include "BLI_ghash.h" -#include "BLI_memarena.h" -#include "BLI_rand.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_key.h" - - -#include "render_types.h" -#include "rendercore.h" -#include "renderdatabase.h" -#include "shading.h" -#include "strand.h" -#include "zbuf.h" - -/* *************** */ - -static float strand_eval_width(Material *ma, float strandco) -{ - float fac; - - strandco= 0.5f*(strandco + 1.0f); - - if (ma->strand_ease!=0.0f) { - if (ma->strand_ease<0.0f) - fac= pow(strandco, 1.0f+ma->strand_ease); - else - fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease)); - } - else fac= strandco; - - return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end); -} - -void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) -{ - Material *ma; - StrandBuffer *strandbuf; - const float *simplify; - float p[4][3], data[4], cross[3], w, dx, dy, t; - int type; - - strandbuf= sseg->buffer; - ma= sseg->buffer->ma; - t= spoint->t; - type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; - - copy_v3_v3(p[0], sseg->v[0]->co); - copy_v3_v3(p[1], sseg->v[1]->co); - copy_v3_v3(p[2], sseg->v[2]->co); - copy_v3_v3(p[3], sseg->v[3]->co); - - if (sseg->obi->flag & R_TRANSFORMED) { - mul_m4_v3(sseg->obi->mat, p[0]); - mul_m4_v3(sseg->obi->mat, p[1]); - mul_m4_v3(sseg->obi->mat, p[2]); - mul_m4_v3(sseg->obi->mat, p[3]); - } - - if (t == 0.0f) { - copy_v3_v3(spoint->co, p[1]); - spoint->strandco= sseg->v[1]->strandco; - - spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); - if (sseg->v[0] != sseg->v[1]) - spoint->dtstrandco *= 0.5f; - } - else if (t == 1.0f) { - copy_v3_v3(spoint->co, p[2]); - spoint->strandco= sseg->v[2]->strandco; - - spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); - if (sseg->v[3] != sseg->v[2]) - spoint->dtstrandco *= 0.5f; - } - else { - key_curve_position_weights(t, data, type); - spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; - spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; - spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; - spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; - } - - key_curve_tangent_weights(t, data, type); - spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; - spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; - spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; - - normalize_v3_v3(spoint->tan, spoint->dtco); - normalize_v3_v3(spoint->nor, spoint->co); - negate_v3(spoint->nor); - - spoint->width= strand_eval_width(ma, spoint->strandco); - - /* simplification */ - simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); - spoint->alpha= (simplify)? simplify[1]: 1.0f; - - /* outer points */ - cross_v3_v3v3(cross, spoint->co, spoint->tan); - - w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; - dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; - dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; - w = sqrtf(dx * dx + dy * dy); - - if (w > 0.0f) { - if (strandbuf->flag & R_STRAND_B_UNITS) { - const float crosslen= len_v3(cross); - w= 2.0f*crosslen*strandbuf->minwidth/w; - - if (spoint->width < w) { - spoint->alpha= spoint->width/w; - spoint->width= w; - } - - if (simplify) - /* squared because we only change width, not length */ - spoint->width *= simplify[0]*simplify[0]; - - mul_v3_fl(cross, spoint->width*0.5f/crosslen); - } - else - mul_v3_fl(cross, spoint->width/w); - } - - sub_v3_v3v3(spoint->co1, spoint->co, cross); - add_v3_v3v3(spoint->co2, spoint->co, cross); - - copy_v3_v3(spoint->dsco, cross); -} - -/* *************** */ - -static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v) -{ - v[0]= negt*v1[0] + t*v2[0]; -} - -static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v) -{ - v[0]= negt*v1[0] + t*v2[0]; - v[1]= negt*v1[1] + t*v2[1]; - v[2]= negt*v1[2] + t*v2[2]; -} - -static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v) -{ - v[0]= negt*v1[0] + t*v2[0]; - v[1]= negt*v1[1] + t*v2[1]; - v[2]= negt*v1[2] + t*v2[2]; - v[3]= negt*v1[3] + t*v2[3]; -} - -static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag) -{ - float negt= 1.0f - t; - - interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined); - - if (addpassflag & SCE_PASS_VECTOR) { - interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed); - } - /* optim... */ - if (addpassflag & ~(SCE_PASS_VECTOR)) { - if (addpassflag & SCE_PASS_Z) - interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z); - if (addpassflag & SCE_PASS_RGBA) - interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col); - if (addpassflag & SCE_PASS_NORMAL) { - interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor); - normalize_v3(shr->nor); - } - if (addpassflag & SCE_PASS_EMIT) - interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit); - if (addpassflag & SCE_PASS_DIFFUSE) { - interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff); - interpolate_vec3(shr1->diffshad, shr2->diffshad, t, negt, shr->diffshad); - } - if (addpassflag & SCE_PASS_SPEC) - interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec); - if (addpassflag & SCE_PASS_SHADOW) - interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad); - if (addpassflag & SCE_PASS_AO) - interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao); - if (addpassflag & SCE_PASS_ENVIRONMENT) - interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env); - if (addpassflag & SCE_PASS_INDIRECT) - interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect); - if (addpassflag & SCE_PASS_REFLECT) - interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl); - if (addpassflag & SCE_PASS_REFRACT) - interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr); - if (addpassflag & SCE_PASS_MIST) - interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist); - } -} - -static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) -{ - if (alpha < 1.0f) { - shr->combined[0] *= alpha; - shr->combined[1] *= alpha; - shr->combined[2] *= alpha; - shr->combined[3] *= alpha; - - shr->col[0] *= alpha; - shr->col[1] *= alpha; - shr->col[2] *= alpha; - shr->col[3] *= alpha; - - shr->alpha *= alpha; - } -} - -static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint) -{ - ShadeInput *shi= ssamp->shi; - ShadeResult *shr= ssamp->shr; - VlakRen vlr; - int seed; - - memset(&vlr, 0, sizeof(vlr)); - vlr.flag= R_SMOOTH; - if (sseg->buffer->ma->mode & MA_TANGENT_STR) - vlr.flag |= R_TANGENT; - - shi->vlr= &vlr; - shi->v1= NULL; - shi->v2= NULL; - shi->v3= NULL; - shi->strand= sseg->strand; - shi->obi= sseg->obi; - shi->obr= sseg->obi->obr; - - /* cache for shadow */ - shi->samplenr= re->shadowsamplenr[shi->thread]++; - - /* all samples */ - shi->mask= 0xFFFF; - - /* seed RNG for consistent results across tiles */ - seed = shi->strand->index + (svert - shi->strand->vert); - BLI_thread_srandom(shi->thread, seed); - - shade_input_set_strand(shi, sseg->strand, spoint); - shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); - - /* init material vars */ - shade_input_init_material(shi); - - /* shade */ - shade_samples_do_AO(ssamp); - shade_input_do_shade(shi, shr); - - /* apply simplification */ - strand_apply_shaderesult_alpha(shr, spoint->alpha); - - /* include lamphalos for strand, since halo layer was added already */ - if (re->flag & R_LAMPHALO) - if (shi->layflag & SCE_LAY_HALO) - renderspothalo(shi, shr->combined, shr->combined[3]); - - shi->strand= NULL; -} - -/* *************** */ - -struct StrandShadeCache { - GHash *resulthash; - GHash *refcounthash; - MemArena *memarena; -}; - -typedef struct StrandCacheEntry { - GHashPair pair; - ShadeResult shr; -} StrandCacheEntry; - -StrandShadeCache *strand_shade_cache_create(void) -{ - StrandShadeCache *cache; - - cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache"); - cache->resulthash= BLI_ghash_pair_new("strand_shade_cache_create1 gh"); - cache->refcounthash= BLI_ghash_pair_new("strand_shade_cache_create2 gh"); - cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena"); - - return cache; -} - -void strand_shade_cache_free(StrandShadeCache *cache) -{ - BLI_ghash_free(cache->refcounthash, NULL, NULL); - BLI_ghash_free(cache->resulthash, MEM_freeN, NULL); - BLI_memarena_free(cache->memarena); - MEM_freeN(cache); -} - -static GHashPair strand_shade_hash_pair(ObjectInstanceRen *obi, StrandVert *svert) -{ - GHashPair pair = {obi, svert}; - return pair; -} - -static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert) -{ - StrandCacheEntry *entry; - StrandPoint p; - int *refcount; - GHashPair pair = strand_shade_hash_pair(sseg->obi, svert); - - entry= BLI_ghash_lookup(cache->resulthash, &pair); - refcount= BLI_ghash_lookup(cache->refcounthash, &pair); - - if (!entry) { - /* not shaded yet, shade and insert into hash */ - p.t= (sseg->v[1] == svert)? 0.0f: 1.0f; - strand_eval_point(sseg, &p); - strand_shade_point(re, ssamp, sseg, svert, &p); - - entry= MEM_callocN(sizeof(StrandCacheEntry), "StrandCacheEntry"); - entry->pair = pair; - entry->shr = ssamp->shr[0]; - BLI_ghash_insert(cache->resulthash, entry, entry); - } - else - /* already shaded, just copy previous result from hash */ - ssamp->shr[0]= entry->shr; - - /* lower reference count and remove if not needed anymore by any samples */ - (*refcount)--; - if (*refcount == 0) { - BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL); - BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL); - } -} - -void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag) -{ - ShadeResult shr1, shr2; - - /* get shading for two endpoints and interpolate */ - strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]); - shr1= ssamp->shr[0]; - strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]); - shr2= ssamp->shr[0]; - - interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag); - - /* apply alpha along width */ - if (sseg->buffer->widthfade != -1.0f) { - s = 1.0f - powf(fabsf(s), sseg->buffer->widthfade); - - strand_apply_shaderesult_alpha(ssamp->shr, s); - } -} - -void strand_shade_unref(StrandShadeCache *cache, ObjectInstanceRen *obi, StrandVert *svert) -{ - GHashPair pair = strand_shade_hash_pair(obi, svert); - int *refcount; - - /* lower reference count and remove if not needed anymore by any samples */ - refcount= BLI_ghash_lookup(cache->refcounthash, &pair); - - (*refcount)--; - if (*refcount == 0) { - BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL); - BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL); - } -} - -static void strand_shade_refcount(StrandShadeCache *cache, StrandSegment *sseg, StrandVert *svert) -{ - GHashPair pair = strand_shade_hash_pair(sseg->obi, svert); - GHashPair *key; - int *refcount= BLI_ghash_lookup(cache->refcounthash, &pair); - - if (!refcount) { - key= BLI_memarena_alloc(cache->memarena, sizeof(GHashPair)); - *key = pair; - refcount= BLI_memarena_alloc(cache->memarena, sizeof(int)); - *refcount= 1; - BLI_ghash_insert(cache->refcounthash, key, refcount); - } - else - (*refcount)++; -} - -/* *************** */ - -typedef struct StrandPart { - Render *re; - ZSpan *zspan; - - APixstrand *apixbuf; - int *totapixbuf; - int *rectz; - int *rectmask; - intptr_t *rectdaps; - int rectx, recty; - int sample; - int shadow; - float (*jit)[2]; - int samples; - - StrandSegment *segment; - float t[3], s[3]; - - StrandShadeCache *cache; -} StrandPart; - -typedef struct StrandSortSegment { - struct StrandSortSegment *next; - int obi, strand, segment; - float z; -} StrandSortSegment; - -static int compare_strand_segment(const void *poin1, const void *poin2) -{ - const StrandSortSegment *seg1= (const StrandSortSegment*)poin1; - const StrandSortSegment *seg2= (const StrandSortSegment*)poin2; - - if (seg1->z < seg2->z) - return -1; - else if (seg1->z == seg2->z) - return 0; - else - return 1; -} - -static void do_strand_point_project(float winmat[4][4], ZSpan *zspan, float *co, float *hoco, float *zco) -{ - projectvert(co, winmat, hoco); - hoco_to_zco(zspan, zco, hoco); -} - -static void strand_project_point(float winmat[4][4], float winx, float winy, StrandPoint *spoint) -{ - float div; - - projectvert(spoint->co, winmat, spoint->hoco); - - div= 1.0f/spoint->hoco[3]; - spoint->x= spoint->hoco[0]*div*winx*0.5f; - spoint->y= spoint->hoco[1]*div*winy*0.5f; -} - -static APixstrand *addpsmainAstrand(ListBase *lb) -{ - APixstrMain *psm; - - psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA"); - BLI_addtail(lb, psm); - psm->ps = MEM_callocN(4096 * sizeof(APixstrand), "pixstr"); - - return psm->ps; -} - -static APixstrand *addpsAstrand(ZSpan *zspan) -{ - /* make new PS */ - if (zspan->apstrandmcounter==0) { - zspan->curpstrand= addpsmainAstrand(zspan->apsmbase); - zspan->apstrandmcounter= 4095; - } - else { - zspan->curpstrand++; - zspan->apstrandmcounter--; - } - return zspan->curpstrand; -} - -#define MAX_ZROW 2000 - -static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z) -{ - StrandPart *spart= (StrandPart *)handle; - StrandShadeCache *cache= spart->cache; - StrandSegment *sseg= spart->segment; - APixstrand *apn, *apnew; - float t, s; - int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0; - - offset = y*spart->rectx + x; - obi= sseg->obi - spart->re->objectinstance; - strnr= sseg->strand->index + 1; - seg= sseg->v[1] - sseg->strand->vert; - mask= (1<<spart->sample); - - /* check against solid z-buffer */ - zverg= (int)z; - - if (spart->rectdaps) { - /* find the z of the sample */ - PixStr *ps; - intptr_t *rd= spart->rectdaps + offset; - - bufferz= 0x7FFFFFFF; - if (spart->rectmask) maskz= 0x7FFFFFFF; - - if (*rd) { - for (ps= (PixStr *)(*rd); ps; ps= ps->next) { - if (mask & ps->mask) { - bufferz= ps->z; - if (spart->rectmask) - maskz= ps->maskz; - break; - } - } - } - } - else { - bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF; - if (spart->rectmask) - maskz= spart->rectmask[offset]; - } - -#define CHECK_ADD(n) \ - if (apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \ - { if (!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } (void)0 -#define CHECK_ASSIGN(n) \ - if (apn->p[n]==0) \ - {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } (void)0 - - /* add to pixel list */ - if (zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) { - if (!spart->rectmask || zverg > maskz) { - t = u * spart->t[0] + v * spart->t[1] + (1.0f - u - v) * spart->t[2]; - s = fabsf(u * spart->s[0] + v * spart->s[1] + (1.0f - u - v) * spart->s[2]); - - apn= spart->apixbuf + offset; - while (apn) { - CHECK_ADD(0); - CHECK_ADD(1); - CHECK_ADD(2); - CHECK_ADD(3); - CHECK_ASSIGN(0); - CHECK_ASSIGN(1); - CHECK_ASSIGN(2); - CHECK_ASSIGN(3); - - apnew= addpsAstrand(spart->zspan); - SWAP(APixstrand, *apnew, *apn); - apn->next= apnew; - CHECK_ASSIGN(0); - } - - if (cache) { - strand_shade_refcount(cache, sseg, sseg->v[1]); - strand_shade_refcount(cache, sseg, sseg->v[2]); - } - spart->totapixbuf[offset]++; - } - } -} - -/* width is calculated in hoco space, to ensure strands are visible */ -static int strand_test_clip(float winmat[4][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy) -{ - float hoco[4]; - int clipflag= 0; - - projectvert(co, winmat, hoco); - - /* we compare z without perspective division for segment sorting */ - *zcomp= hoco[2]; - - if (hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1; - else if (hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2; - - if (hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4; - else if (hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8; - - clipflag |= testclip(hoco); - - return clipflag; -} - -static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample) -{ - float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy; - - copy_v3_v3(jco1, co1); - copy_v3_v3(jco2, co2); - copy_v3_v3(jco3, co3); - copy_v3_v3(jco4, co4); - - if (spart->jit) { - jx= -spart->jit[sample][0]; - jy= -spart->jit[sample][1]; - - jco1[0] += jx; jco1[1] += jy; - jco2[0] += jx; jco2[1] += jy; - jco3[0] += jx; jco3[1] += jy; - jco4[0] += jx; jco4[1] += jy; - - /* XXX mblur? */ - } - - spart->sample= sample; - - spart->t[0]= t-dt; - spart->s[0]= -1.0f; - spart->t[1]= t-dt; - spart->s[1]= 1.0f; - spart->t[2]= t; - spart->s[2]= 1.0f; - zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac); - spart->t[0]= t-dt; - spart->s[0]= -1.0f; - spart->t[1]= t; - spart->s[1]= 1.0f; - spart->t[2]= t; - spart->s[2]= -1.0f; - zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac); -} - -static void strand_render(Render *re, StrandSegment *sseg, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2) -{ - if (spart) { - float t= p2->t; - float dt= p2->t - p1->t; - int a; - - for (a=0; a<spart->samples; a++) - do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a); - } - else { - float hoco1[4], hoco2[4]; - int a, obi, index; - - obi= sseg->obi - re->objectinstance; - index= sseg->strand->index; - - projectvert(p1->co, winmat, hoco1); - projectvert(p2->co, winmat, hoco2); - - - for (a=0; a<totzspan; a++) { -#if 0 - /* render both strand and single pixel wire to counter aliasing */ - zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2); -#endif - /* only render a line for now, which makes the shadow map more - * similar across frames, and so reduces flicker */ - zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2); - } - } -} - -static int strand_segment_recursive(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth) -{ - StrandPoint p; - StrandBuffer *buffer= sseg->buffer; - float dot, d1[2], d2[2], len1, len2; - - if (depth == buffer->maxdepth) - return 0; - - p.t= (p1->t + p2->t)*0.5f; - strand_eval_point(sseg, &p); - strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p); - - d1[0]= (p.x - p1->x); - d1[1]= (p.y - p1->y); - len1= d1[0]*d1[0] + d1[1]*d1[1]; - - d2[0]= (p2->x - p.x); - d2[1]= (p2->y - p.y); - len2= d2[0]*d2[0] + d2[1]*d2[1]; - - if (len1 == 0.0f || len2 == 0.0f) - return 0; - - dot= d1[0]*d2[0] + d1[1]*d2[1]; - if (dot*dot > sseg->sqadaptcos*len1*len2) - return 0; - - if (spart) { - do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1); - do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2); - } - else { -#if 0 - projectvert(p.co1, winmat, p.hoco1); - projectvert(p.co2, winmat, p.hoco2); - p.clip1= testclip(p.hoco1); - p.clip2= testclip(p.hoco2); -#endif - } - - if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1)) - strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p); - if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1)) - strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2); - - return 1; -} - -void render_strand_segment(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg) -{ - StrandBuffer *buffer= sseg->buffer; - StrandPoint *p1= &sseg->point1; - StrandPoint *p2= &sseg->point2; - - p1->t= 0.0f; - p2->t= 1.0f; - - strand_eval_point(sseg, p1); - strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1); - strand_eval_point(sseg, p2); - strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2); - - if (spart) { - do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1); - do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2); - do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1); - do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2); - } - else { -#if 0 - projectvert(p1->co1, winmat, p1->hoco1); - projectvert(p1->co2, winmat, p1->hoco2); - projectvert(p2->co1, winmat, p2->hoco1); - projectvert(p2->co2, winmat, p2->hoco2); - p1->clip1= testclip(p1->hoco1); - p1->clip2= testclip(p1->hoco2); - p2->clip1= testclip(p2->hoco1); - p2->clip2= testclip(p2->hoco2); -#endif - } - - if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0)) - strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2); -} - -/* render call to fill in strands */ -int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache) -{ - ObjectRen *obr; - ObjectInstanceRen *obi; - ZSpan zspan; - StrandRen *strand = NULL; - StrandVert *svert; - StrandBound *sbound; - StrandPart spart; - StrandSegment sseg; - StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; - MemArena *memarena; - float z[4], bounds[4], obwinmat[4][4]; - int a, b, c, i, totsegment, clip[4]; - - if (re->test_break(re->tbh)) - return 0; - if (re->totstrand == 0) - return 0; - - /* setup StrandPart */ - memset(&spart, 0, sizeof(spart)); - - spart.re= re; - spart.rectx= pa->rectx; - spart.recty= pa->recty; - spart.apixbuf= apixbuf; - spart.zspan= &zspan; - spart.rectdaps= pa->rectdaps; - spart.rectz= pa->rectz; - spart.rectmask= pa->rectmask; - spart.cache= cache; - spart.shadow= shadow; - spart.jit= jit; - spart.samples= samples; - - zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop); - - /* needed for transform from hoco to zbuffer co */ - zspan.zmulx= ((float)winx)/2.0f; - zspan.zmuly= ((float)winy)/2.0f; - - zspan.zofsx= -pa->disprect.xmin; - zspan.zofsy= -pa->disprect.ymin; - - /* to center the sample position */ - if (!shadow) { - zspan.zofsx -= 0.5f; - zspan.zofsy -= 0.5f; - } - - zspan.apsmbase= apsmbase; - - /* clipping setup */ - bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx; - bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx; - bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy; - bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy; - - memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena"); - firstseg= NULL; - totsegment= 0; - - /* for all object instances */ - for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { - Material *ma; - float widthx, widthy; - - obr= obi->obr; - - if (!obr->strandbuf || !(obr->strandbuf->lay & lay)) - continue; - - /* compute matrix and try clipping whole object */ - if (obi->flag & R_TRANSFORMED) - mul_m4_m4m4(obwinmat, winmat, obi->mat); - else - copy_m4_m4(obwinmat, winmat); - - /* test if we should skip it */ - ma = obr->strandbuf->ma; - - if (shadow && (!(ma->mode2 & MA_CASTSHADOW) || !(ma->mode & MA_SHADBUF))) - continue; - else if (!shadow && (ma->mode & MA_ONLYCAST)) - continue; - - if (clip_render_object(obi->obr->boundbox, bounds, obwinmat)) - continue; - - widthx= obr->strandbuf->maxwidth*obwinmat[0][0]; - widthy= obr->strandbuf->maxwidth*obwinmat[1][1]; - - /* for each bounding box containing a number of strands */ - sbound= obr->strandbuf->bound; - for (c=0; c<obr->strandbuf->totbound; c++, sbound++) { - if (clip_render_object(sbound->boundbox, bounds, obwinmat)) - continue; - - /* for each strand in this bounding box */ - for (a=sbound->start; a<sbound->end; a++) { - strand= RE_findOrAddStrand(obr, a); - svert= strand->vert; - - /* keep clipping and z depth for 4 control points */ - clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy); - clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy); - clip[0]= clip[1]; z[0]= z[1]; - - for (b=0; b<strand->totvert-1; b++, svert++) { - /* compute 4th point clipping and z depth */ - if (b < strand->totvert-2) { - clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy); - } - else { - clip[3]= clip[2]; z[3]= z[2]; - } - - /* check clipping and add to sortsegments buffer */ - if (!(clip[0] & clip[1] & clip[2] & clip[3])) { - sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); - sortseg->obi= i; - sortseg->strand= strand->index; - sortseg->segment= b; - - sortseg->z= 0.5f*(z[1] + z[2]); - - sortseg->next= firstseg; - firstseg= sortseg; - totsegment++; - } - - /* shift clipping and z depth */ - clip[0]= clip[1]; z[0]= z[1]; - clip[1]= clip[2]; z[1]= z[2]; - clip[2]= clip[3]; z[2]= z[3]; - } - } - } - } - - if (!re->test_break(re->tbh)) { - /* convert list to array and sort */ - sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment"); - for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next) - sortsegments[a]= *sortseg; - qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment); - } - - BLI_memarena_free(memarena); - - spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf"); - - if (!re->test_break(re->tbh)) { - /* render segments in sorted order */ - sortseg= sortsegments; - for (a=0; a<totsegment; a++, sortseg++) { - if (re->test_break(re->tbh)) - break; - - obi= &re->objectinstance[sortseg->obi]; - obr= obi->obr; - - sseg.obi= obi; - sseg.strand= RE_findOrAddStrand(obr, sortseg->strand); - sseg.buffer= sseg.strand->buffer; - sseg.sqadaptcos= sseg.buffer->adaptcos; - sseg.sqadaptcos *= sseg.sqadaptcos; - - svert= sseg.strand->vert + sortseg->segment; - sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert; - sseg.v[1]= svert; - sseg.v[2]= svert+1; - sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1; - sseg.shaded= 0; - - spart.segment= &sseg; - - render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg); - } - } - - if (sortsegments) - MEM_freeN(sortsegments); - MEM_freeN(spart.totapixbuf); - - zbuf_free_span(&zspan); - - return totsegment; -} - -/* *************** */ - -StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[4][4], int timeoffset) -{ - StrandSurface *mesh; - MFace *mface; - MVert *mvert; - float (*co)[3]; - int a, totvert, totface; - - totvert= dm->getNumVerts(dm); - totface= dm->getNumTessFaces(dm); - - for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) { - if ((mesh->obr.ob == obr->ob) && - (mesh->obr.par == obr->par) && - (mesh->obr.index == obr->index) && - (mesh->totvert == totvert) && - (mesh->totface == totface)) - { - break; - } - } - - if (!mesh) { - mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface"); - mesh->obr= *obr; - mesh->totvert= totvert; - mesh->totface= totface; - mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); - mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO"); - mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv"); - mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect"); - BLI_addtail(&re->strandsurface, mesh); - } - - if (timeoffset == -1 && !mesh->prevco) - mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); - else if (timeoffset == 0 && !mesh->co) - mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); - else if (timeoffset == 1 && !mesh->nextco) - mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); - else - return mesh; - - mvert= dm->getVertArray(dm); - for (a=0; a<mesh->totvert; a++, mvert++) { - copy_v3_v3(co[a], mvert->co); - mul_m4_v3(mat, co[a]); - } - - mface= dm->getTessFaceArray(dm); - for (a=0; a<mesh->totface; a++, mface++) { - mesh->face[a][0]= mface->v1; - mesh->face[a][1]= mface->v2; - mesh->face[a][2]= mface->v3; - mesh->face[a][3]= mface->v4; - } - - return mesh; -} - -void free_strand_surface(Render *re) -{ - StrandSurface *mesh; - - for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) { - if (mesh->co) MEM_freeN(mesh->co); - if (mesh->prevco) MEM_freeN(mesh->prevco); - if (mesh->nextco) MEM_freeN(mesh->nextco); - if (mesh->ao) MEM_freeN(mesh->ao); - if (mesh->env) MEM_freeN(mesh->env); - if (mesh->indirect) MEM_freeN(mesh->indirect); - if (mesh->face) MEM_freeN(mesh->face); - } - - BLI_freelistN(&re->strandsurface); -} - -void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width) -{ - StrandVert *svert; - const float width2 = width * 2.0f; - float vec[3]; - int a; - - for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) { - copy_v3_v3(vec, svert->co); - minmax_v3v3_v3(min, max, vec); - - if (width!=0.0f) { - add_v3_fl(vec, width); - minmax_v3v3_v3(min, max, vec); - add_v3_fl(vec, -width2); - minmax_v3v3_v3(min, max, vec); - } - } -} - |