void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; size_t i; int a, p_id; MTFace *mtface; MFace *mface; /* we can't bake in edit mode */ if (me->edit_btmesh) return; bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); /* initialize all pixel arrays so we know which ones are 'blank' */ for (i = 0; i < num_pixels; i++) { pixel_array[i].primitive_id = -1; } for (i = 0; i < bake_images->size; i++) { zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); } else { int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer); mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id); } mface = CustomData_get_layer(&me->fdata, CD_MFACE); if (mtface == NULL) return; p_id = -1; for (i = 0; i < me->totface; i++) { float vec[4][2]; MTFace *mtf = &mtface[i]; MFace *mf = &mface[i]; int mat_nr = mf->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; for (a = 0; a < 4; a++) { /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); /* 4 vertices in the face */ if (mf->v4 != 0) { bd.primitive_id = ++p_id; bake_differentials(&bd, vec[0], vec[2], vec[3]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel); } } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(bd.zspan); }
/* already have tested for tface and ima and zspan */ static void shade_tface(BakeShade *bs) { VlakRen *vlr = bs->vlr; ObjectInstanceRen *obi = bs->obi; ObjectRen *obr = obi->obr; MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); Image *ima = tface->tpage; float vec[4][2]; int a, i1, i2, i3; /* check valid zspan */ if (ima != bs->ima) { BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); bs->ima = ima; bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL, IMA_IBUF_IMA); /* note, these calls only free/fill contents of zspan struct, not zspan itself */ zbuf_free_span(bs->zspan); zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); } bs->rectx = bs->ibuf->x; bs->recty = bs->ibuf->y; bs->rect = bs->ibuf->rect; bs->rect_colorspace = bs->ibuf->rect_colorspace; bs->rect_float = bs->ibuf->rect_float; bs->vcol = NULL; bs->quad = 0; bs->rect_mask = NULL; bs->displacement_buffer = NULL; if (bs->use_mask || bs->use_displacement_buffer) { BakeImBufuserData *userdata = bs->ibuf->userdata; if (userdata == NULL) { BLI_lock_thread(LOCK_CUSTOM1); userdata = bs->ibuf->userdata; if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */ userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData"); if (bs->use_mask) { if (userdata->mask_buffer == NULL) { userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask"); } } if (bs->use_displacement_buffer) { if (userdata->displacement_buffer == NULL) { userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); } } bs->ibuf->userdata = userdata; BLI_unlock_thread(LOCK_CUSTOM1); } bs->rect_mask = userdata->mask_buffer; bs->displacement_buffer = userdata->displacement_buffer; } /* get pixel level vertex coordinates */ for (a = 0; a < 4; a++) { /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f); vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f); } /* UV indices have to be corrected for possible quad->tria splits */ i1 = 0; i2 = 1; i3 = 2; vlr_set_uv_indices(vlr, &i1, &i2, &i3); bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]); zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade); if (vlr->v4) { bs->quad = 1; bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]); zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade); } }
void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; size_t i; int a, p_id; const MLoopUV *mloopuv; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; #ifdef USE_MFACE_WORKAROUND unsigned int mpoly_prev_testindex = UINT_MAX; #endif /* we can't bake in edit mode */ if (me->edit_btmesh) return; if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } else { int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer); mloopuv = CustomData_get_layer_n(&me->ldata, CD_MTFACE, uv_id); } if (mloopuv == NULL) return; bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); /* initialize all pixel arrays so we know which ones are 'blank' */ for (i = 0; i < num_pixels; i++) { pixel_array[i].primitive_id = -1; } for (i = 0; i < bake_images->size; i++) { zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); p_id = -1; for (i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; const MPoly *mp = &me->mpoly[lt->poly]; float vec[3][2]; int mat_nr = mp->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; #ifdef USE_MFACE_WORKAROUND if (lt->poly != mpoly_prev_testindex) { test_index_face_looptri(mp, me->mloop, &looptri[i]); mpoly_prev_testindex = lt->poly; } #endif for (a = 0; a < 3; a++) { const float *uv = mloopuv[lt->tri[a]].uv; /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(looptri); MEM_freeN(bd.zspan); }
/* 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], int winx, int winy, int UNUSED(sample), float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache) { ObjectRen *obr; ObjectInstanceRen *obi; ZSpan zspan; StrandRen *strand=0; 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; 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) mult_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->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; }