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