Blender V2.61 - r43446

strand.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: none of this file.
00022  *
00023  * Contributors: Brecht Van Lommel.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <math.h>
00034 #include <string.h>
00035 #include <stdlib.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "DNA_key_types.h"
00040 #include "DNA_material_types.h"
00041 #include "DNA_meshdata_types.h"
00042 
00043 #include "BLI_math.h"
00044 #include "BLI_blenlib.h"
00045 #include "BLI_utildefines.h"
00046 #include "BLI_ghash.h"
00047 #include "BLI_memarena.h"
00048 #include "BLI_rand.h"
00049 
00050 #include "BKE_DerivedMesh.h"
00051 #include "BKE_key.h"
00052 
00053 
00054 #include "render_types.h"
00055 #include "initrender.h"
00056 #include "rendercore.h"
00057 #include "renderdatabase.h"
00058 #include "renderpipeline.h"
00059 #include "pixelblending.h"
00060 #include "shading.h"
00061 #include "strand.h"
00062 #include "zbuf.h"
00063 
00064 /* to be removed */
00065 void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco);
00066 void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) );
00067 void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, float *ho1, float *ho2);
00068 
00069 /* *************** */
00070 
00071 static float strand_eval_width(Material *ma, float strandco)
00072 {
00073     float fac;
00074 
00075     strandco= 0.5f*(strandco + 1.0f);
00076 
00077     if(ma->strand_ease!=0.0f) {
00078         if(ma->strand_ease<0.0f)
00079             fac= pow(strandco, 1.0f+ma->strand_ease);
00080         else
00081             fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease));
00082     }
00083     else fac= strandco;
00084     
00085     return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
00086 }
00087 
00088 void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
00089 {
00090     Material *ma;
00091     StrandBuffer *strandbuf;
00092     float *simplify;
00093     float p[4][3], data[4], cross[3], w, dx, dy, t;
00094     int type;
00095 
00096     strandbuf= sseg->buffer;
00097     ma= sseg->buffer->ma;
00098     t= spoint->t;
00099     type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL;
00100 
00101     copy_v3_v3(p[0], sseg->v[0]->co);
00102     copy_v3_v3(p[1], sseg->v[1]->co);
00103     copy_v3_v3(p[2], sseg->v[2]->co);
00104     copy_v3_v3(p[3], sseg->v[3]->co);
00105 
00106     if(sseg->obi->flag & R_TRANSFORMED) {
00107         mul_m4_v3(sseg->obi->mat, p[0]);
00108         mul_m4_v3(sseg->obi->mat, p[1]);
00109         mul_m4_v3(sseg->obi->mat, p[2]);
00110         mul_m4_v3(sseg->obi->mat, p[3]);
00111     }
00112 
00113     if(t == 0.0f) {
00114         copy_v3_v3(spoint->co, p[1]);
00115         spoint->strandco= sseg->v[1]->strandco;
00116 
00117         spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco);
00118         if(sseg->v[0] != sseg->v[1])
00119             spoint->dtstrandco *= 0.5f;
00120     }
00121     else if(t == 1.0f) {
00122         copy_v3_v3(spoint->co, p[2]);
00123         spoint->strandco= sseg->v[2]->strandco;
00124 
00125         spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco);
00126         if(sseg->v[3] != sseg->v[2])
00127             spoint->dtstrandco *= 0.5f;
00128     }
00129     else {
00130         key_curve_position_weights(t, data, type);
00131         spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
00132         spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
00133         spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
00134         spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco;
00135     }
00136 
00137     key_curve_tangent_weights(t, data, type);
00138     spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
00139     spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
00140     spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
00141 
00142     normalize_v3_v3(spoint->tan, spoint->dtco);
00143     normalize_v3_v3(spoint->nor, spoint->co);
00144     negate_v3(spoint->nor);
00145 
00146     spoint->width= strand_eval_width(ma, spoint->strandco);
00147     
00148     /* simplification */
00149     simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0);
00150     spoint->alpha= (simplify)? simplify[1]: 1.0f;
00151 
00152     /* outer points */
00153     cross_v3_v3v3(cross, spoint->co, spoint->tan);
00154 
00155     w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
00156     dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
00157     dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
00158     w= sqrt(dx*dx + dy*dy);
00159 
00160     if(w > 0.0f) {
00161         if(strandbuf->flag & R_STRAND_B_UNITS) {
00162             const float crosslen= len_v3(cross);
00163             w= 2.0f*crosslen*strandbuf->minwidth/w;
00164 
00165             if(spoint->width < w) {
00166                 spoint->alpha= spoint->width/w;
00167                 spoint->width= w;
00168             }
00169 
00170             if(simplify)
00171                 /* squared because we only change width, not length */
00172                 spoint->width *= simplify[0]*simplify[0];
00173 
00174             mul_v3_fl(cross, spoint->width*0.5f/crosslen);
00175         }
00176         else
00177             mul_v3_fl(cross, spoint->width/w);
00178     }
00179 
00180     sub_v3_v3v3(spoint->co1, spoint->co, cross);
00181     add_v3_v3v3(spoint->co2, spoint->co, cross);
00182 
00183     copy_v3_v3(spoint->dsco, cross);
00184 }
00185 
00186 /* *************** */
00187 
00188 static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v)
00189 {
00190     v[0]= negt*v1[0] + t*v2[0];
00191 }
00192 
00193 static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
00194 {
00195     v[0]= negt*v1[0] + t*v2[0];
00196     v[1]= negt*v1[1] + t*v2[1];
00197     v[2]= negt*v1[2] + t*v2[2];
00198 }
00199 
00200 static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v)
00201 {
00202     v[0]= negt*v1[0] + t*v2[0];
00203     v[1]= negt*v1[1] + t*v2[1];
00204     v[2]= negt*v1[2] + t*v2[2];
00205     v[3]= negt*v1[3] + t*v2[3];
00206 }
00207 
00208 static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
00209 {
00210     float negt= 1.0f - t;
00211 
00212     interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined);
00213 
00214     if(addpassflag & SCE_PASS_VECTOR) {
00215         interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed);
00216     }
00217     /* optim... */
00218     if(addpassflag & ~(SCE_PASS_VECTOR)) {
00219         if(addpassflag & SCE_PASS_Z)
00220             interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z);
00221         if(addpassflag & SCE_PASS_RGBA)
00222             interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col);
00223         if(addpassflag & SCE_PASS_NORMAL) {
00224             interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor);
00225             normalize_v3(shr->nor);
00226         }
00227         if(addpassflag & SCE_PASS_EMIT)
00228             interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit);
00229         if(addpassflag & SCE_PASS_DIFFUSE)
00230             interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff);
00231         if(addpassflag & SCE_PASS_SPEC)
00232             interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec);
00233         if(addpassflag & SCE_PASS_SHADOW)
00234             interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad);
00235         if(addpassflag & SCE_PASS_AO)
00236             interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao);
00237         if(addpassflag & SCE_PASS_ENVIRONMENT)
00238             interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env);
00239         if(addpassflag & SCE_PASS_INDIRECT)
00240             interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect);
00241         if(addpassflag & SCE_PASS_REFLECT)
00242             interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl);
00243         if(addpassflag & SCE_PASS_REFRACT)
00244             interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
00245         if(addpassflag & SCE_PASS_MIST)
00246             interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist);
00247     }
00248 }
00249 
00250 static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha)
00251 {
00252     if(alpha < 1.0f) {
00253         shr->combined[0] *= alpha;
00254         shr->combined[1] *= alpha;
00255         shr->combined[2] *= alpha;
00256         shr->combined[3] *= alpha;
00257 
00258         shr->col[0] *= alpha;
00259         shr->col[1] *= alpha;
00260         shr->col[2] *= alpha;
00261         shr->col[3] *= alpha;
00262 
00263         shr->alpha *= alpha;
00264     }
00265 }
00266 
00267 static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint)
00268 {
00269     ShadeInput *shi= ssamp->shi;
00270     ShadeResult *shr= ssamp->shr;
00271     VlakRen vlr;
00272     int seed;
00273 
00274     memset(&vlr, 0, sizeof(vlr));
00275     vlr.flag= R_SMOOTH;
00276     if(sseg->buffer->ma->mode & MA_TANGENT_STR)
00277         vlr.flag |= R_TANGENT;
00278 
00279     shi->vlr= &vlr;
00280     shi->v1= NULL;
00281     shi->v2= NULL;
00282     shi->v3= NULL;
00283     shi->strand= sseg->strand;
00284     shi->obi= sseg->obi;
00285     shi->obr= sseg->obi->obr;
00286 
00287     /* cache for shadow */
00288     shi->samplenr= re->shadowsamplenr[shi->thread]++;
00289 
00290     /* all samples */
00291     shi->mask= 0xFFFF;
00292 
00293     /* seed RNG for consistent results across tiles */
00294     seed = shi->strand->index + (svert - shi->strand->vert);
00295     BLI_thread_srandom(shi->thread, seed);
00296 
00297     shade_input_set_strand(shi, sseg->strand, spoint);
00298     shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
00299     
00300     /* init material vars */
00301     shade_input_init_material(shi);
00302     
00303     /* shade */
00304     shade_samples_do_AO(ssamp);
00305     shade_input_do_shade(shi, shr);
00306 
00307     /* apply simplification */
00308     strand_apply_shaderesult_alpha(shr, spoint->alpha);
00309 
00310     /* include lamphalos for strand, since halo layer was added already */
00311     if(re->flag & R_LAMPHALO)
00312         if(shi->layflag & SCE_LAY_HALO)
00313             renderspothalo(shi, shr->combined, shr->combined[3]);
00314     
00315     shi->strand= NULL;
00316 }
00317 
00318 /* *************** */
00319 
00320 struct StrandShadeCache {
00321     GHash *resulthash;
00322     GHash *refcounthash;
00323     MemArena *memarena;
00324 };
00325 
00326 StrandShadeCache *strand_shade_cache_create(void)
00327 {
00328     StrandShadeCache *cache;
00329 
00330     cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache");
00331     cache->resulthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "strand_shade_cache_create1 gh");
00332     cache->refcounthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "strand_shade_cache_create2 gh");
00333     cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena");
00334     
00335     return cache;
00336 }
00337 
00338 void strand_shade_cache_free(StrandShadeCache *cache)
00339 {
00340     BLI_ghash_free(cache->refcounthash, NULL, NULL);
00341     BLI_ghash_free(cache->resulthash, NULL, (GHashValFreeFP)MEM_freeN);
00342     BLI_memarena_free(cache->memarena);
00343     MEM_freeN(cache);
00344 }
00345 
00346 static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert)
00347 {
00348     ShadeResult *hashshr;
00349     StrandPoint p;
00350     int *refcount;
00351 
00352     hashshr= BLI_ghash_lookup(cache->resulthash, svert);
00353     refcount= BLI_ghash_lookup(cache->refcounthash, svert);
00354 
00355     if(!hashshr) {
00356         /* not shaded yet, shade and insert into hash */
00357         p.t= (sseg->v[1] == svert)? 0.0f: 1.0f;
00358         strand_eval_point(sseg, &p);
00359         strand_shade_point(re, ssamp, sseg, svert, &p);
00360 
00361         hashshr= MEM_callocN(sizeof(ShadeResult), "HashShadeResult");
00362         *hashshr= ssamp->shr[0];
00363         BLI_ghash_insert(cache->resulthash, svert, hashshr);
00364     }
00365     else
00366         /* already shaded, just copy previous result from hash */
00367         ssamp->shr[0]= *hashshr;
00368     
00369     /* lower reference count and remove if not needed anymore by any samples */
00370     (*refcount)--;
00371     if(*refcount == 0) {
00372         BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN);
00373         BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL);
00374     }
00375 }
00376 
00377 void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag)
00378 {
00379     ShadeResult shr1, shr2;
00380 
00381     /* get shading for two endpoints and interpolate */
00382     strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]);
00383     shr1= ssamp->shr[0];
00384     strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]);
00385     shr2= ssamp->shr[0];
00386 
00387     interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag);
00388 
00389     /* apply alpha along width */
00390     if(sseg->buffer->widthfade != 0.0f) {
00391         s = 1.0f - pow(fabs(s), sseg->buffer->widthfade);
00392 
00393         strand_apply_shaderesult_alpha(ssamp->shr, s);
00394     }
00395 }
00396 
00397 void strand_shade_unref(StrandShadeCache *cache, StrandVert *svert)
00398 {
00399     int *refcount;
00400 
00401     /* lower reference count and remove if not needed anymore by any samples */
00402     refcount= BLI_ghash_lookup(cache->refcounthash, svert);
00403 
00404     (*refcount)--;
00405     if(*refcount == 0) {
00406         BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN);
00407         BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL);
00408     }
00409 }
00410 
00411 static void strand_shade_refcount(StrandShadeCache *cache, StrandVert *svert)
00412 {
00413     int *refcount= BLI_ghash_lookup(cache->refcounthash, svert);
00414 
00415     if(!refcount) {
00416         refcount= BLI_memarena_alloc(cache->memarena, sizeof(int));
00417         *refcount= 1;
00418         BLI_ghash_insert(cache->refcounthash, svert, refcount);
00419     }
00420     else
00421         (*refcount)++;
00422 }
00423 
00424 /* *************** */
00425 
00426 typedef struct StrandPart {
00427     Render *re;
00428     ZSpan *zspan;
00429 
00430     APixstrand *apixbuf;
00431     int *totapixbuf;
00432     int *rectz;
00433     int *rectmask;
00434     intptr_t *rectdaps;
00435     int rectx, recty;
00436     int sample;
00437     int shadow;
00438     float (*jit)[2];
00439 
00440     StrandSegment *segment;
00441     float t[3], s[3];
00442 
00443     StrandShadeCache *cache;
00444 } StrandPart;
00445 
00446 typedef struct StrandSortSegment {
00447     struct StrandSortSegment *next;
00448     int obi, strand, segment;
00449     float z;
00450 } StrandSortSegment;
00451 
00452 static int compare_strand_segment(const void *poin1, const void *poin2)
00453 {
00454     const StrandSortSegment *seg1= (const StrandSortSegment*)poin1;
00455     const StrandSortSegment *seg2= (const StrandSortSegment*)poin2;
00456 
00457     if(seg1->z < seg2->z)
00458         return -1;
00459     else if(seg1->z == seg2->z)
00460         return 0;
00461     else
00462         return 1;
00463 }
00464 
00465 static void do_strand_point_project(float winmat[][4], ZSpan *zspan, float *co, float *hoco, float *zco)
00466 {
00467     projectvert(co, winmat, hoco);
00468     hoco_to_zco(zspan, zco, hoco);
00469 }
00470 
00471 static void strand_project_point(float winmat[][4], float winx, float winy, StrandPoint *spoint)
00472 {
00473     float div;
00474 
00475     projectvert(spoint->co, winmat, spoint->hoco);
00476 
00477     div= 1.0f/spoint->hoco[3];
00478     spoint->x= spoint->hoco[0]*div*winx*0.5f;
00479     spoint->y= spoint->hoco[1]*div*winy*0.5f;
00480 }
00481 
00482 static APixstrand *addpsmainAstrand(ListBase *lb)
00483 {
00484     APixstrMain *psm;
00485 
00486     psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
00487     BLI_addtail(lb, psm);
00488     psm->ps= MEM_callocN(4096*sizeof(APixstrand),"pixstr");
00489 
00490     return psm->ps;
00491 }
00492 
00493 static APixstrand *addpsAstrand(ZSpan *zspan)
00494 {
00495     /* make new PS */
00496     if(zspan->apstrandmcounter==0) {
00497         zspan->curpstrand= addpsmainAstrand(zspan->apsmbase);
00498         zspan->apstrandmcounter= 4095;
00499     }
00500     else {
00501         zspan->curpstrand++;
00502         zspan->apstrandmcounter--;
00503     }
00504     return zspan->curpstrand;
00505 }
00506 
00507 #define MAX_ZROW    2000
00508 
00509 static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z)
00510 {
00511     StrandPart *spart= (StrandPart*)handle;
00512     StrandShadeCache *cache= spart->cache;
00513     StrandSegment *sseg= spart->segment;
00514     APixstrand *apn, *apnew;
00515     float t, s;
00516     int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0;
00517 
00518     offset = y*spart->rectx + x;
00519     obi= sseg->obi - spart->re->objectinstance;
00520     strnr= sseg->strand->index + 1;
00521     seg= sseg->v[1] - sseg->strand->vert;
00522     mask= (1<<spart->sample);
00523 
00524     /* check against solid z-buffer */
00525     zverg= (int)z;
00526 
00527     if(spart->rectdaps) {
00528         /* find the z of the sample */
00529         PixStr *ps;
00530         intptr_t *rd= spart->rectdaps + offset;
00531         
00532         bufferz= 0x7FFFFFFF;
00533         if(spart->rectmask) maskz= 0x7FFFFFFF;
00534         
00535         if(*rd) {   
00536             for(ps= (PixStr *)(*rd); ps; ps= ps->next) {
00537                 if(mask & ps->mask) {
00538                     bufferz= ps->z;
00539                     if(spart->rectmask)
00540                         maskz= ps->maskz;
00541                     break;
00542                 }
00543             }
00544         }
00545     }
00546     else {
00547         bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF;
00548         if(spart->rectmask)
00549             maskz= spart->rectmask[offset];
00550     }
00551 
00552 #define CHECK_ADD(n) \
00553     if(apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \
00554     { if(!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; }
00555 #define CHECK_ASSIGN(n) \
00556     if(apn->p[n]==0) \
00557     {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; }
00558 
00559     /* add to pixel list */
00560     if(zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) {
00561         if(!spart->rectmask || zverg > maskz) {
00562             t = u*spart->t[0] + v*spart->t[1] + (1.0f-u-v)*spart->t[2];
00563             s = fabs(u*spart->s[0] + v*spart->s[1] + (1.0f-u-v)*spart->s[2]);
00564 
00565             apn= spart->apixbuf + offset;
00566             while(apn) {
00567                 CHECK_ADD(0);
00568                 CHECK_ADD(1);
00569                 CHECK_ADD(2);
00570                 CHECK_ADD(3);
00571                 CHECK_ASSIGN(0);
00572                 CHECK_ASSIGN(1);
00573                 CHECK_ASSIGN(2);
00574                 CHECK_ASSIGN(3);
00575 
00576                 apnew= addpsAstrand(spart->zspan);
00577                 SWAP(APixstrand, *apnew, *apn);
00578                 apn->next= apnew;
00579                 CHECK_ASSIGN(0);
00580             }
00581 
00582             if(cache) {
00583                 strand_shade_refcount(cache, sseg->v[1]);
00584                 strand_shade_refcount(cache, sseg->v[2]);
00585             }
00586             spart->totapixbuf[offset]++;
00587         }
00588     }
00589 }
00590 
00591 /* width is calculated in hoco space, to ensure strands are visible */
00592 static int strand_test_clip(float winmat[][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy)
00593 {
00594     float hoco[4];
00595     int clipflag= 0;
00596 
00597     projectvert(co, winmat, hoco);
00598 
00599     /* we compare z without perspective division for segment sorting */
00600     *zcomp= hoco[2];
00601 
00602     if(hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1;
00603     else if(hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2;
00604     
00605     if(hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4;
00606     else if(hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8;
00607 
00608     clipflag |= testclip(hoco);
00609 
00610     return clipflag;
00611 }
00612 
00613 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)
00614 {
00615     float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy;
00616 
00617     copy_v3_v3(jco1, co1);
00618     copy_v3_v3(jco2, co2);
00619     copy_v3_v3(jco3, co3);
00620     copy_v3_v3(jco4, co4);
00621 
00622     if(spart->jit) {
00623         jx= -spart->jit[sample][0];
00624         jy= -spart->jit[sample][1];
00625 
00626         jco1[0] += jx; jco1[1] += jy;
00627         jco2[0] += jx; jco2[1] += jy;
00628         jco3[0] += jx; jco3[1] += jy;
00629         jco4[0] += jx; jco4[1] += jy;
00630 
00631         /* XXX mblur? */
00632     }
00633 
00634     spart->sample= sample;
00635 
00636     spart->t[0]= t-dt;
00637     spart->s[0]= -1.0f;
00638     spart->t[1]= t-dt;
00639     spart->s[1]= 1.0f;
00640     spart->t[2]= t;
00641     spart->s[2]= 1.0f;
00642     zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac);
00643     spart->t[0]= t-dt;
00644     spart->s[0]= -1.0f;
00645     spart->t[1]= t;
00646     spart->s[1]= 1.0f;
00647     spart->t[2]= t;
00648     spart->s[2]= -1.0f;
00649     zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac);
00650 }
00651 
00652 static void strand_render(Render *re, StrandSegment *sseg, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2)
00653 {
00654     if(spart) {
00655         float t= p2->t;
00656         float dt= p2->t - p1->t;
00657         int a;
00658 
00659         if(re->osa) {
00660             for(a=0; a<re->osa; a++)
00661                 do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a);
00662         }
00663         else
00664             do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, 0);
00665     }
00666     else {
00667         float hoco1[4], hoco2[4];
00668         int a, obi, index;
00669   
00670         obi= sseg->obi - re->objectinstance;
00671         index= sseg->strand->index;
00672 
00673         projectvert(p1->co, winmat, hoco1);
00674         projectvert(p2->co, winmat, hoco2);
00675 
00676   
00677         for(a=0; a<totzspan; a++) {
00678 #if 0
00679             /* render both strand and single pixel wire to counter aliasing */
00680             zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2);
00681 #endif
00682             /* only render a line for now, which makes the shadow map more
00683                similiar across frames, and so reduces flicker */
00684             zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2);
00685         }
00686     }
00687 }
00688 
00689 static int strand_segment_recursive(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
00690 {
00691     StrandPoint p;
00692     StrandBuffer *buffer= sseg->buffer;
00693     float dot, d1[2], d2[2], len1, len2;
00694 
00695     if(depth == buffer->maxdepth)
00696         return 0;
00697 
00698     p.t= (p1->t + p2->t)*0.5f;
00699     strand_eval_point(sseg, &p);
00700     strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p);
00701 
00702     d1[0]= (p.x - p1->x);
00703     d1[1]= (p.y - p1->y);
00704     len1= d1[0]*d1[0] + d1[1]*d1[1];
00705 
00706     d2[0]= (p2->x - p.x);
00707     d2[1]= (p2->y - p.y);
00708     len2= d2[0]*d2[0] + d2[1]*d2[1];
00709 
00710     if(len1 == 0.0f || len2 == 0.0f)
00711         return 0;
00712     
00713     dot= d1[0]*d2[0] + d1[1]*d2[1];
00714     if(dot*dot > sseg->sqadaptcos*len1*len2)
00715         return 0;
00716 
00717     if(spart) {
00718         do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1);
00719         do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2);
00720     }
00721     else {
00722 #if 0
00723         projectvert(p.co1, winmat, p.hoco1);
00724         projectvert(p.co2, winmat, p.hoco2);
00725         p.clip1= testclip(p.hoco1);
00726         p.clip2= testclip(p.hoco2);
00727 #endif
00728     }
00729 
00730     if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1))
00731         strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p);
00732     if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1))
00733         strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2);
00734     
00735     return 1;
00736 }
00737 
00738 void render_strand_segment(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg)
00739 {
00740     StrandBuffer *buffer= sseg->buffer;
00741     StrandPoint *p1= &sseg->point1;
00742     StrandPoint *p2= &sseg->point2;
00743 
00744     p1->t= 0.0f;
00745     p2->t= 1.0f;
00746 
00747     strand_eval_point(sseg, p1);
00748     strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1);
00749     strand_eval_point(sseg, p2);
00750     strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2);
00751 
00752     if(spart) {
00753         do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1);
00754         do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2);
00755         do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1);
00756         do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2);
00757     }
00758     else {
00759 #if 0
00760         projectvert(p1->co1, winmat, p1->hoco1);
00761         projectvert(p1->co2, winmat, p1->hoco2);
00762         projectvert(p2->co1, winmat, p2->hoco1);
00763         projectvert(p2->co2, winmat, p2->hoco2);
00764         p1->clip1= testclip(p1->hoco1);
00765         p1->clip2= testclip(p1->hoco2);
00766         p2->clip1= testclip(p2->hoco1);
00767         p2->clip2= testclip(p2->hoco2);
00768 #endif
00769     }
00770 
00771     if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0))
00772         strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2);
00773 }
00774 
00775 /* render call to fill in strands */
00776 int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[][4], int winx, int winy, int UNUSED(sample), float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache)
00777 {
00778     ObjectRen *obr;
00779     ObjectInstanceRen *obi;
00780     ZSpan zspan;
00781     StrandRen *strand=0;
00782     StrandVert *svert;
00783     StrandBound *sbound;
00784     StrandPart spart;
00785     StrandSegment sseg;
00786     StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
00787     MemArena *memarena;
00788     float z[4], bounds[4], obwinmat[4][4];
00789     int a, b, c, i, totsegment, clip[4];
00790 
00791     if(re->test_break(re->tbh))
00792         return 0;
00793     if(re->totstrand == 0)
00794         return 0;
00795 
00796     /* setup StrandPart */
00797     memset(&spart, 0, sizeof(spart));
00798 
00799     spart.re= re;
00800     spart.rectx= pa->rectx;
00801     spart.recty= pa->recty;
00802     spart.apixbuf= apixbuf;
00803     spart.zspan= &zspan;
00804     spart.rectdaps= pa->rectdaps;
00805     spart.rectz= pa->rectz;
00806     spart.rectmask= pa->rectmask;
00807     spart.cache= cache;
00808     spart.shadow= shadow;
00809     spart.jit= jit;
00810 
00811     zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop);
00812 
00813     /* needed for transform from hoco to zbuffer co */
00814     zspan.zmulx= ((float)winx)/2.0f;
00815     zspan.zmuly= ((float)winy)/2.0f;
00816     
00817     zspan.zofsx= -pa->disprect.xmin;
00818     zspan.zofsy= -pa->disprect.ymin;
00819 
00820     /* to center the sample position */
00821     if(!shadow) {
00822         zspan.zofsx -= 0.5f;
00823         zspan.zofsy -= 0.5f;
00824     }
00825 
00826     zspan.apsmbase= apsmbase;
00827 
00828     /* clipping setup */
00829     bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
00830     bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
00831     bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
00832     bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
00833 
00834     memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena");
00835     firstseg= NULL;
00836     totsegment= 0;
00837 
00838     /* for all object instances */
00839     for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
00840         Material *ma;
00841         float widthx, widthy;
00842 
00843         obr= obi->obr;
00844 
00845         if(!obr->strandbuf || !(obr->strandbuf->lay & lay))
00846             continue;
00847 
00848         /* compute matrix and try clipping whole object */
00849         if(obi->flag & R_TRANSFORMED)
00850             mult_m4_m4m4(obwinmat, winmat, obi->mat);
00851         else
00852             copy_m4_m4(obwinmat, winmat);
00853 
00854         /* test if we should skip it */
00855         ma = obr->strandbuf->ma;
00856 
00857         if(shadow && !(ma->mode & MA_SHADBUF))
00858             continue;
00859         else if(!shadow && (ma->mode & MA_ONLYCAST))
00860             continue;
00861 
00862         if(clip_render_object(obi->obr->boundbox, bounds, obwinmat))
00863             continue;
00864         
00865         widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
00866         widthy= obr->strandbuf->maxwidth*obwinmat[1][1];
00867 
00868         /* for each bounding box containing a number of strands */
00869         sbound= obr->strandbuf->bound;
00870         for(c=0; c<obr->strandbuf->totbound; c++, sbound++) {
00871             if(clip_render_object(sbound->boundbox, bounds, obwinmat))
00872                 continue;
00873 
00874             /* for each strand in this bounding box */
00875             for(a=sbound->start; a<sbound->end; a++) {
00876                 strand= RE_findOrAddStrand(obr, a);
00877                 svert= strand->vert;
00878 
00879                 /* keep clipping and z depth for 4 control points */
00880                 clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
00881                 clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
00882                 clip[0]= clip[1]; z[0]= z[1];
00883 
00884                 for(b=0; b<strand->totvert-1; b++, svert++) {
00885                     /* compute 4th point clipping and z depth */
00886                     if(b < strand->totvert-2) {
00887                         clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
00888                     }
00889                     else {
00890                         clip[3]= clip[2]; z[3]= z[2];
00891                     }
00892 
00893                     /* check clipping and add to sortsegments buffer */
00894                     if(!(clip[0] & clip[1] & clip[2] & clip[3])) {
00895                         sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
00896                         sortseg->obi= i;
00897                         sortseg->strand= strand->index;
00898                         sortseg->segment= b;
00899 
00900                         sortseg->z= 0.5f*(z[1] + z[2]);
00901 
00902                         sortseg->next= firstseg;
00903                         firstseg= sortseg;
00904                         totsegment++;
00905                     }
00906 
00907                     /* shift clipping and z depth */
00908                     clip[0]= clip[1]; z[0]= z[1];
00909                     clip[1]= clip[2]; z[1]= z[2];
00910                     clip[2]= clip[3]; z[2]= z[3];
00911                 }
00912             }
00913         }
00914     }
00915 
00916     if(!re->test_break(re->tbh)) {
00917         /* convert list to array and sort */
00918         sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
00919         for(a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
00920             sortsegments[a]= *sortseg;
00921         qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
00922     }
00923 
00924     BLI_memarena_free(memarena);
00925 
00926     spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");
00927 
00928     if(!re->test_break(re->tbh)) {
00929         /* render segments in sorted order */
00930         sortseg= sortsegments;
00931         for(a=0; a<totsegment; a++, sortseg++) {
00932             if(re->test_break(re->tbh))
00933                 break;
00934 
00935             obi= &re->objectinstance[sortseg->obi];
00936             obr= obi->obr;
00937 
00938             sseg.obi= obi;
00939             sseg.strand= RE_findOrAddStrand(obr, sortseg->strand);
00940             sseg.buffer= sseg.strand->buffer;
00941             sseg.sqadaptcos= sseg.buffer->adaptcos;
00942             sseg.sqadaptcos *= sseg.sqadaptcos;
00943 
00944             svert= sseg.strand->vert + sortseg->segment;
00945             sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
00946             sseg.v[1]= svert;
00947             sseg.v[2]= svert+1;
00948             sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
00949             sseg.shaded= 0;
00950 
00951             spart.segment= &sseg;
00952 
00953             render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
00954         }
00955     }
00956 
00957     if(sortsegments)
00958         MEM_freeN(sortsegments);
00959     MEM_freeN(spart.totapixbuf);
00960     
00961     zbuf_free_span(&zspan);
00962 
00963     return totsegment;
00964 }
00965 
00966 /* *************** */
00967 
00968 StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[][4], int timeoffset)
00969 {
00970     StrandSurface *mesh;
00971     MFace *mface;
00972     MVert *mvert;
00973     float (*co)[3];
00974     int a, totvert, totface;
00975 
00976     totvert= dm->getNumVerts(dm);
00977     totface= dm->getNumFaces(dm);
00978 
00979     for(mesh=re->strandsurface.first; mesh; mesh=mesh->next)
00980         if(mesh->obr.ob == obr->ob && mesh->obr.par == obr->par
00981             && mesh->obr.index == obr->index && mesh->totvert==totvert && mesh->totface==totface)
00982             break;
00983 
00984     if(!mesh) {
00985         mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface");
00986         mesh->obr= *obr;
00987         mesh->totvert= totvert;
00988         mesh->totface= totface;
00989         mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces");
00990         mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO");
00991         mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv");
00992         mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect");
00993         BLI_addtail(&re->strandsurface, mesh);
00994     }
00995 
00996     if(timeoffset == -1 && !mesh->prevco)
00997         mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
00998     else if(timeoffset == 0 && !mesh->co)
00999         mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
01000     else if(timeoffset == 1 && !mesh->nextco)
01001         mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
01002     else
01003         return mesh;
01004 
01005     mvert= dm->getVertArray(dm);
01006     for(a=0; a<mesh->totvert; a++, mvert++) {
01007         copy_v3_v3(co[a], mvert->co);
01008         mul_m4_v3(mat, co[a]);
01009     }
01010 
01011     mface= dm->getFaceArray(dm);
01012     for(a=0; a<mesh->totface; a++, mface++) {
01013         mesh->face[a][0]= mface->v1;
01014         mesh->face[a][1]= mface->v2;
01015         mesh->face[a][2]= mface->v3;
01016         mesh->face[a][3]= mface->v4;
01017     }
01018 
01019     return mesh;
01020 }
01021 
01022 void free_strand_surface(Render *re)
01023 {
01024     StrandSurface *mesh;
01025 
01026     for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
01027         if(mesh->co) MEM_freeN(mesh->co);
01028         if(mesh->prevco) MEM_freeN(mesh->prevco);
01029         if(mesh->nextco) MEM_freeN(mesh->nextco);
01030         if(mesh->ao) MEM_freeN(mesh->ao);
01031         if(mesh->env) MEM_freeN(mesh->env);
01032         if(mesh->indirect) MEM_freeN(mesh->indirect);
01033         if(mesh->face) MEM_freeN(mesh->face);
01034     }
01035 
01036     BLI_freelistN(&re->strandsurface);
01037 }
01038 
01039 void strand_minmax(StrandRen *strand, float *min, float *max, float width)
01040 {
01041     StrandVert *svert;
01042     float vec[3], width2= 2.0f*width;
01043     int a;
01044 
01045     for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
01046         copy_v3_v3(vec, svert->co);
01047         DO_MINMAX(vec, min, max);
01048         
01049         if(width!=0.0f) {
01050             vec[0]+= width; vec[1]+= width; vec[2]+= width;
01051             DO_MINMAX(vec, min, max);
01052             vec[0]-= width2; vec[1]-= width2; vec[2]-= width2;
01053             DO_MINMAX(vec, min, max);
01054         }
01055     }
01056 }
01057