diff options
Diffstat (limited to 'source/blender/render/intern/source/renderdatabase.c')
-rw-r--r-- | source/blender/render/intern/source/renderdatabase.c | 1603 |
1 files changed, 1603 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c new file mode 100644 index 00000000000..67bfd1bfdc7 --- /dev/null +++ b/source/blender/render/intern/source/renderdatabase.c @@ -0,0 +1,1603 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006, Blender Foundation, full recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/renderdatabase.c + * \ingroup render + */ + + +/* + * Storage, retrieval and query of render specific data. + * + * All data from a Blender scene is converted by the renderconverter/ + * into a special format that is used by the render module to make + * images out of. These functions interface to the render-specific + * database. + * + * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data + * entries each. + * + * The index of an entry is >>8 (the highest 24 * bits), to find an + * offset in a 256-entry block. + * + * - If the 256-entry block entry has an entry in the + * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in + * that block is allocated to this entry. + * + * - If the entry has no block allocated for it yet, memory is + * allocated. + * + * The pointer to the correct entry is returned. Memory is guaranteed + * to exist (as long as the malloc does not break). Since guarded + * allocation is used, memory _must_ be available. Otherwise, an + * exit(0) would occur. + * + */ + +#include <limits.h> +#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_hash.h" + +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_texture_types.h" +#include "DNA_listBase.h" +#include "DNA_particle_types.h" + +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "rayintersection.h" +#include "rayobject.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "zbuf.h" + +/* ------------------------------------------------------------------------- */ + +/* More dynamic allocation of options for render vertices and faces, so we don't + * have to reserve this space inside vertices. + * Important; vertices and faces, should have been created already (to get tables + * checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not + * the index */ + +/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */ +#define RE_STRESS_ELEMS 1 +#define RE_RAD_ELEMS 4 +#define RE_STRAND_ELEMS 1 +#define RE_TANGENT_ELEMS 3 +#define RE_WINSPEED_ELEMS 4 +#define RE_MTFACE_ELEMS 1 +#define RE_MCOL_ELEMS 4 +#define RE_UV_ELEMS 2 +#define RE_VLAK_ORIGINDEX_ELEMS 1 +#define RE_VERT_ORIGINDEX_ELEMS 1 +#define RE_SURFNOR_ELEMS 3 +#define RE_RADFACE_ELEMS 1 +#define RE_SIMPLIFY_ELEMS 2 +#define RE_FACE_ELEMS 1 +#define RE_NMAP_TANGENT_ELEMS 16 + +float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify) +{ + float *stress; + int nr= ver->index>>8; + + stress= obr->vertnodes[nr].stress; + if (stress==NULL) { + if (verify) + stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table"); + else + return NULL; + } + return stress + (ver->index & 255)*RE_STRESS_ELEMS; +} + +/* this one callocs! */ +float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify) +{ + float *rad; + int nr= ver->index>>8; + + rad= obr->vertnodes[nr].rad; + if (rad==NULL) { + if (verify) + rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table"); + else + return NULL; + } + return rad + (ver->index & 255)*RE_RAD_ELEMS; +} + +float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify) +{ + float *strand; + int nr= ver->index>>8; + + strand= obr->vertnodes[nr].strand; + if (strand==NULL) { + if (verify) + strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table"); + else + return NULL; + } + return strand + (ver->index & 255)*RE_STRAND_ELEMS; +} + +/* needs calloc */ +float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify) +{ + float *tangent; + int nr= ver->index>>8; + + tangent= obr->vertnodes[nr].tangent; + if (tangent==NULL) { + if (verify) + tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table"); + else + return NULL; + } + return tangent + (ver->index & 255)*RE_TANGENT_ELEMS; +} + +/* needs calloc! not all renderverts have them */ +/* also winspeed is exception, it is stored per instance */ +float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify) +{ + float *winspeed; + int totvector; + + winspeed= obi->vectors; + if (winspeed==NULL) { + if (verify) { + totvector= obi->obr->totvert + obi->obr->totstrand; + winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table"); + } + else + return NULL; + } + return winspeed + ver->index*RE_WINSPEED_ELEMS; +} + +int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify) +{ + int *origindex; + int nr= ver->index>>8; + + origindex= obr->vertnodes[nr].origindex; + if (origindex==NULL) { + if (verify) + origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS; +} + +VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver) +{ + VertRen *v1= RE_findOrAddVert(obr, obr->totvert++); + float *fp1, *fp2; + int *int1, *int2; + int index= v1->index; + + *v1= *ver; + v1->index= index; + + fp1= RE_vertren_get_stress(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_stress(obr, v1, 1); + memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_rad(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_rad(obr, v1, 1); + memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_strand(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_strand(obr, v1, 1); + memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_tangent(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_tangent(obr, v1, 1); + memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float)); + } + int1= RE_vertren_get_origindex(obr, ver, 0); + if (int1) { + int2= RE_vertren_get_origindex(obr, v1, 1); + memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int)); + } + return v1; +} + +VertRen *RE_findOrAddVert(ObjectRen *obr, int nr) +{ + VertTableNode *temp; + VertRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddVert: %d\n", nr); + return NULL; + } + a= nr>>8; + + if (a>=obr->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->vertnodes; + + obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE), "vertnodes"); + if (temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode)); + memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode)); + + obr->vertnodeslen+=TABLEINITSIZE; + if (temp) MEM_freeN(temp); + } + + v= obr->vertnodes[a].vert; + if (v==NULL) { + int i; + + v= (VertRen *)MEM_callocN(256*sizeof(VertRen), "findOrAddVert"); + obr->vertnodes[a].vert= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) { + v[a].index= i; + } + } + v+= (nr & 255); + return v; +} + +/* ------------------------------------------------------------------------ */ + +MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify) +{ + VlakTableNode *node; + int nr= vlr->index>>8, vlakindex= (vlr->index&255); + int index= (n<<8) + vlakindex; + + node= &obr->vlaknodes[nr]; + + if (verify) { + if (n>=node->totmtface) { + MTFace *mtface= node->mtface; + int size= (n+1)*256; + + node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface"); + + if (mtface) { + size= node->totmtface*256; + memcpy(node->mtface, mtface, size*sizeof(MTFace)); + MEM_freeN(mtface); + } + + node->totmtface= n+1; + } + } + else { + if (n>=node->totmtface) + return NULL; + + if (name) *name= obr->mtface[n]; + } + + return node->mtface + index; +} + +MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify) +{ + VlakTableNode *node; + int nr= vlr->index>>8, vlakindex= (vlr->index&255); + int index= (n<<8) + vlakindex; + + node= &obr->vlaknodes[nr]; + + if (verify) { + if (n>=node->totmcol) { + MCol *mcol= node->mcol; + int size= (n+1)*256; + + node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol"); + + if (mcol) { + size= node->totmcol*256; + memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS); + MEM_freeN(mcol); + } + + node->totmcol= n+1; + } + } + else { + if (n>=node->totmcol) + return NULL; + + if (name) *name= obr->mcol[n]; + } + + return node->mcol + index*RE_MCOL_ELEMS; +} + +int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify) +{ + int *origindex; + int nr= vlak->index>>8; + + origindex= obr->vlaknodes[nr].origindex; + if (origindex==NULL) { + if (verify) + origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS; +} + +float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify) +{ + float *surfnor; + int nr= vlak->index>>8; + + surfnor= obr->vlaknodes[nr].surfnor; + if (surfnor==NULL) { + if (verify) + surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table"); + else + return NULL; + } + return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS; +} + +float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify) +{ + float **tangents; + int nr= vlak->index>>8; + + tangents = obr->vlaknodes[nr].tangent_arrays; + + if (index + 1 > 8) { + return NULL; + } + + index = index < 0 ? 0: index; + + if (tangents[index] == NULL) { + if (verify) { + tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table"); + } + else + return NULL; + } + + return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS; +} + +RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify) +{ + RadFace **radface; + int nr= vlak->index>>8; + + radface= obr->vlaknodes[nr].radface; + if (radface==NULL) { + if (verify) + radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table"); + else + return NULL; + } + return radface + (vlak->index & 255)*RE_RADFACE_ELEMS; +} + +VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) +{ + VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++); + MTFace *mtface, *mtface1; + MCol *mcol, *mcol1; + float *surfnor, *surfnor1; + float *tangent, *tangent1; + int *origindex, *origindex1; + RadFace **radface, **radface1; + int i, index = vlr1->index; + char *name; + + *vlr1= *vlr; + vlr1->index= index; + + for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) { + mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1); + memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS); + } + + for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) { + mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1); + memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS); + } + + origindex= RE_vlakren_get_origindex(obr, vlr, 0); + if (origindex) { + origindex1= RE_vlakren_get_origindex(obr, vlr1, 1); + /* Just an int, but memcpy for consistency. */ + memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS); + } + + surfnor= RE_vlakren_get_surfnor(obr, vlr, 0); + if (surfnor) { + surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1); + copy_v3_v3(surfnor1, surfnor); + } + + for (i=0; i < MAX_MTFACE; i++) { + tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false); + if (!tangent) + continue; + tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true); + memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS); + } + + radface= RE_vlakren_get_radface(obr, vlr, 0); + if (radface) { + radface1= RE_vlakren_get_radface(obr, vlr1, 1); + *radface1= *radface; + } + + return vlr1; +} + +void RE_vlakren_get_normal(Render *UNUSED(re), ObjectInstanceRen *obi, VlakRen *vlr, float r_nor[3]) +{ + float (*nmat)[3]= obi->nmat; + + if (obi->flag & R_TRANSFORMED) { + mul_v3_m3v3(r_nor, nmat, vlr->n); + normalize_v3(r_nor); + } + else { + copy_v3_v3(r_nor, vlr->n); + } +} + +void RE_set_customdata_names(ObjectRen *obr, CustomData *data) +{ + /* CustomData layer names are stored per object here, because the + * DerivedMesh which stores the layers is freed */ + + CustomDataLayer *layer; + int numtf = 0, numcol = 0, i, mtfn, mcn; + + if (CustomData_has_layer(data, CD_MTFACE)) { + numtf= CustomData_number_of_layers(data, CD_MTFACE); + obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames"); + } + + if (CustomData_has_layer(data, CD_MCOL)) { + numcol= CustomData_number_of_layers(data, CD_MCOL); + obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames"); + } + + for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) { + layer= &data->layers[i]; + + if (layer->type == CD_MTFACE) { + BLI_strncpy(obr->mtface[mtfn++], layer->name, sizeof(layer->name)); + obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf); + obr->bakemtface= layer->active; + } + else if (layer->type == CD_MCOL) { + BLI_strncpy(obr->mcol[mcn++], layer->name, sizeof(layer->name)); + obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol); + } + } +} + +VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr) +{ + VlakTableNode *temp; + VlakRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddVlak: %d\n", nr); + return obr->vlaknodes[0].vlak; + } + a= nr>>8; + + if (a>=obr->vlaknodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->vlaknodes; + + obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE), "vlaknodes"); + if (temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode)); + memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode)); + + obr->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + v= obr->vlaknodes[a].vlak; + + if (v==NULL) { + int i; + + v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen), "findOrAddVlak"); + obr->vlaknodes[a].vlak= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) + v[a].index= i; + } + v+= (nr & 255); + return v; +} + +/* ------------------------------------------------------------------------ */ + +float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify) +{ + float *surfnor; + int nr= strand->index>>8; + + surfnor= obr->strandnodes[nr].surfnor; + if (surfnor==NULL) { + if (verify) + surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table"); + else + return NULL; + } + return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS; +} + +float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify) +{ + StrandTableNode *node; + int nr= strand->index>>8, strandindex= (strand->index&255); + int index= (n<<8) + strandindex; + + node= &obr->strandnodes[nr]; + + if (verify) { + if (n>=node->totuv) { + float *uv= node->uv; + int size= (n+1)*256; + + node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table"); + + if (uv) { + size= node->totuv*256; + memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS); + MEM_freeN(uv); + } + + node->totuv= n+1; + } + } + else { + if (n>=node->totuv) + return NULL; + + if (name) *name= obr->mtface[n]; + } + + return node->uv + index*RE_UV_ELEMS; +} + +MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify) +{ + StrandTableNode *node; + int nr= strand->index>>8, strandindex= (strand->index&255); + int index= (n<<8) + strandindex; + + node= &obr->strandnodes[nr]; + + if (verify) { + if (n>=node->totmcol) { + MCol *mcol= node->mcol; + int size= (n+1)*256; + + node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table"); + + if (mcol) { + size= node->totmcol*256; + memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS); + MEM_freeN(mcol); + } + + node->totmcol= n+1; + } + } + else { + if (n>=node->totmcol) + return NULL; + + if (name) *name= obr->mcol[n]; + } + + return node->mcol + index*RE_MCOL_ELEMS; +} + +float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify) +{ + float *simplify; + int nr= strand->index>>8; + + simplify= obr->strandnodes[nr].simplify; + if (simplify==NULL) { + if (verify) + simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table"); + else + return NULL; + } + return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS; +} + +int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify) +{ + int *face; + int nr= strand->index>>8; + + face= obr->strandnodes[nr].face; + if (face==NULL) { + if (verify) + face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table"); + else + return NULL; + } + return face + (strand->index & 255)*RE_FACE_ELEMS; +} + +/* winspeed is exception, it is stored per instance */ +float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify) +{ + float *winspeed; + int totvector; + + winspeed= obi->vectors; + if (winspeed==NULL) { + if (verify) { + totvector= obi->obr->totvert + obi->obr->totstrand; + winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table"); + } + else + return NULL; + } + return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS; +} + +StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr) +{ + StrandTableNode *temp; + StrandRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddStrand: %d\n", nr); + return obr->strandnodes[0].strand; + } + a= nr>>8; + + if (a>=obr->strandnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->strandnodes; + + obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE), "strandnodes"); + if (temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode)); + memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode)); + + obr->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + v= obr->strandnodes[a].strand; + + if (v==NULL) { + int i; + + v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen), "findOrAddStrand"); + obr->strandnodes[a].strand= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) + v[a].index= i; + } + v+= (nr & 255); + return v; +} + +StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert) +{ + StrandBuffer *strandbuf; + + strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer"); + strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert"); + strandbuf->totvert= totvert; + strandbuf->obr= obr; + + obr->strandbuf= strandbuf; + + return strandbuf; +} + +/* ------------------------------------------------------------------------ */ + +ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay) +{ + ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct"); + + BLI_addtail(&re->objecttable, obr); + obr->ob= ob; + obr->par= par; + obr->index= index; + obr->psysindex= psysindex; + obr->lay= lay; + + return obr; +} + +void free_renderdata_vertnodes(VertTableNode *vertnodes) +{ + int a; + + if (vertnodes==NULL) return; + + for (a=0; vertnodes[a].vert; a++) { + MEM_freeN(vertnodes[a].vert); + + if (vertnodes[a].rad) + MEM_freeN(vertnodes[a].rad); + if (vertnodes[a].strand) + MEM_freeN(vertnodes[a].strand); + if (vertnodes[a].tangent) + MEM_freeN(vertnodes[a].tangent); + if (vertnodes[a].stress) + MEM_freeN(vertnodes[a].stress); + if (vertnodes[a].winspeed) + MEM_freeN(vertnodes[a].winspeed); + if (vertnodes[a].origindex) + MEM_freeN(vertnodes[a].origindex); + } + + MEM_freeN(vertnodes); +} + +void free_renderdata_vlaknodes(VlakTableNode *vlaknodes) +{ + int a; + + if (vlaknodes==NULL) return; + + for (a=0; vlaknodes[a].vlak; a++) { + MEM_freeN(vlaknodes[a].vlak); + + if (vlaknodes[a].mtface) + MEM_freeN(vlaknodes[a].mtface); + if (vlaknodes[a].mcol) + MEM_freeN(vlaknodes[a].mcol); + if (vlaknodes[a].origindex) + MEM_freeN(vlaknodes[a].origindex); + if (vlaknodes[a].surfnor) + MEM_freeN(vlaknodes[a].surfnor); + for (int b = 0; b < MAX_MTFACE; b++) { + if (vlaknodes[a].tangent_arrays[b]) + MEM_freeN(vlaknodes[a].tangent_arrays[b]); + } + if (vlaknodes[a].radface) + MEM_freeN(vlaknodes[a].radface); + } + + MEM_freeN(vlaknodes); +} + +static void free_renderdata_strandnodes(StrandTableNode *strandnodes) +{ + int a; + + if (strandnodes==NULL) return; + + for (a=0; strandnodes[a].strand; a++) { + MEM_freeN(strandnodes[a].strand); + + if (strandnodes[a].uv) + MEM_freeN(strandnodes[a].uv); + if (strandnodes[a].mcol) + MEM_freeN(strandnodes[a].mcol); + if (strandnodes[a].winspeed) + MEM_freeN(strandnodes[a].winspeed); + if (strandnodes[a].surfnor) + MEM_freeN(strandnodes[a].surfnor); + if (strandnodes[a].simplify) + MEM_freeN(strandnodes[a].simplify); + if (strandnodes[a].face) + MEM_freeN(strandnodes[a].face); + } + + MEM_freeN(strandnodes); +} + +void free_renderdata_tables(Render *re) +{ + ObjectInstanceRen *obi; + ObjectRen *obr; + StrandBuffer *strandbuf; + int a=0; + + for (obr=re->objecttable.first; obr; obr=obr->next) { + if (obr->vertnodes) { + free_renderdata_vertnodes(obr->vertnodes); + obr->vertnodes= NULL; + obr->vertnodeslen= 0; + } + + if (obr->vlaknodes) { + free_renderdata_vlaknodes(obr->vlaknodes); + obr->vlaknodes= NULL; + obr->vlaknodeslen= 0; + obr->totvlak= 0; + } + + if (obr->bloha) { + for (a=0; obr->bloha[a]; a++) + MEM_freeN(obr->bloha[a]); + + MEM_freeN(obr->bloha); + obr->bloha= NULL; + obr->blohalen= 0; + } + + if (obr->strandnodes) { + free_renderdata_strandnodes(obr->strandnodes); + obr->strandnodes= NULL; + obr->strandnodeslen= 0; + } + + strandbuf= obr->strandbuf; + if (strandbuf) { + if (strandbuf->vert) MEM_freeN(strandbuf->vert); + if (strandbuf->bound) MEM_freeN(strandbuf->bound); + MEM_freeN(strandbuf); + } + + if (obr->mtface) + MEM_freeN(obr->mtface); + + if (obr->mcol) + MEM_freeN(obr->mcol); + + if (obr->rayfaces) { + MEM_freeN(obr->rayfaces); + obr->rayfaces = NULL; + } + + if (obr->rayprimitives) { + MEM_freeN(obr->rayprimitives); + obr->rayprimitives = NULL; + } + + if (obr->raytree) { + RE_rayobject_free(obr->raytree); + obr->raytree = NULL; + } + } + + if (re->objectinstance) { + for (obi=re->instancetable.first; obi; obi=obi->next) { + if (obi->vectors) + MEM_freeN(obi->vectors); + + if (obi->raytree) + RE_rayobject_free(obi->raytree); + } + + MEM_freeN(re->objectinstance); + re->objectinstance= NULL; + re->totinstance= 0; + re->instancetable.first= re->instancetable.last= NULL; + } + + if (re->sortedhalos) { + MEM_freeN(re->sortedhalos); + re->sortedhalos= NULL; + } + + BLI_freelistN(&re->customdata_names); + BLI_freelistN(&re->objecttable); + BLI_freelistN(&re->instancetable); +} + +/* ------------------------------------------------------------------------ */ + +HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr) +{ + HaloRen *h, **temp; + int a; + + if (nr<0) { + printf("error in findOrAddHalo: %d\n", nr); + return NULL; + } + a= nr>>8; + + if (a>=obr->blohalen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + //printf("Allocating %i more halo groups. %i total.\n", + // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE ); + temp=obr->bloha; + + obr->bloha = (HaloRen **)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha"); + if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *)); + memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *)); + obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + h= obr->bloha[a]; + if (h==NULL) { + h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen), "findOrAdHalo"); + obr->bloha[a]= h; + } + h+= (nr & 255); + return h; +} + +/* ------------------------------------------------------------------------- */ + +HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, + const float vec[3], const float vec1[3], + const float *orco, float hasize, float vectsize, int seed) +{ + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + HaloRen *har; + MTex *mtex; + float tin, tr, tg, tb, ta; + float xn, yn, zn, texvec[3], hoco[4], hoco1[4]; + + if (hasize==0.0f) return NULL; + + projectverto(vec, re->winmat, hoco); + if (hoco[3]==0.0f) return NULL; + if (vec1) { + projectverto(vec1, re->winmat, hoco1); + if (hoco1[3]==0.0f) return NULL; + } + + har= RE_findOrAddHalo(obr, obr->tothalo++); + copy_v3_v3(har->co, vec); + har->hasize= hasize; + + /* actual projectvert is done in function project_renderdata() because of parts/border/pano */ + /* we do it here for sorting of halos */ + zn= hoco[3]; + har->xs= 0.5f*re->winx*(hoco[0]/zn); + har->ys= 0.5f*re->winy*(hoco[1]/zn); + har->zs= 0x7FFFFF*(hoco[2]/zn); + + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + /* halovect */ + if (vec1) { + + har->type |= HA_VECT; + + xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); + yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; + else zn = atan2f(yn, xn); + + har->sin = sinf(zn); + har->cos = cosf(zn); + zn= len_v3v3(vec1, vec); + + har->hasize= vectsize*zn + (1.0f-vectsize)*hasize; + + sub_v3_v3v3(har->no, vec, vec1); + normalize_v3(har->no); + } + + if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA; + + har->alfa= ma->alpha; + har->r= ma->r; + har->g= ma->g; + har->b= ma->b; + har->add= (255.0f*ma->add); + har->mat= ma; + har->hard= ma->har; + har->seed= seed % 256; + + if (ma->mode & MA_STAR) har->starpoints= ma->starc; + if (ma->mode & MA_HALO_LINES) har->linec= ma->linec; + if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc; + if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec; + + + if (ma->mtex[0]) { + + if (ma->mode & MA_HALOTEX) { + har->tex = 1; + } + else if (har->mat->septex & (1 << 0)) { + /* only 1 level textures */ + } + else { + mtex= ma->mtex[0]; + copy_v3_v3(texvec, vec); + + if (mtex->texco & TEXCO_NORM) { + ; + } + else if (mtex->texco & TEXCO_OBJECT) { + /* texvec[0]+= imatbase->ivec[0]; */ + /* texvec[1]+= imatbase->ivec[1]; */ + /* texvec[2]+= imatbase->ivec[2]; */ + /* mul_m3_v3(imatbase->imat, texvec); */ + } + else { + if (orco) { + copy_v3_v3(texvec, orco); + } + } + + externtex(mtex, + texvec, + &tin, &tr, &tg, &tb, &ta, + 0, + re->pool, + skip_load_image, + texnode_preview); + + yn= tin*mtex->colfac; + //zn= tin*mtex->alphafac; + + if (mtex->mapto & MAP_COL) { + zn= 1.0f-yn; + har->r= (yn*tr+ zn*ma->r); + har->g= (yn*tg+ zn*ma->g); + har->b= (yn*tb+ zn*ma->b); + } + if (mtex->texco & TEXCO_UV) { + har->alfa= tin; + } + if (mtex->mapto & MAP_ALPHA) + har->alfa= tin; + } + } + + har->pool = re->pool; + har->skip_load_image = skip_load_image; + har->texnode_preview = texnode_preview; + + return har; +} + +HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, + const float vec[3], const float vec1[3], + const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3]) +{ + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + HaloRen *har; + MTex *mtex; + float tin, tr, tg, tb, ta; + float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3], tex[3], out[3]; + int i, hasrgb; + + if (hasize==0.0f) return NULL; + + projectverto(vec, re->winmat, hoco); + if (hoco[3]==0.0f) return NULL; + if (vec1) { + projectverto(vec1, re->winmat, hoco1); + if (hoco1[3]==0.0f) return NULL; + } + + har= RE_findOrAddHalo(obr, obr->tothalo++); + copy_v3_v3(har->co, vec); + har->hasize= hasize; + + /* actual projectvert is done in function project_renderdata() because of parts/border/pano */ + /* we do it here for sorting of halos */ + zn= hoco[3]; + har->xs= 0.5f*re->winx*(hoco[0]/zn); + har->ys= 0.5f*re->winy*(hoco[1]/zn); + har->zs= 0x7FFFFF*(hoco[2]/zn); + + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + /* halovect */ + if (vec1) { + + har->type |= HA_VECT; + + xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); + yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; + else zn = atan2f(yn, xn); + + har->sin = sinf(zn); + har->cos = cosf(zn); + zn= len_v3v3(vec1, vec)*0.5f; + + har->hasize= vectsize*zn + (1.0f-vectsize)*hasize; + + sub_v3_v3v3(har->no, vec, vec1); + normalize_v3(har->no); + } + + if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA; + + har->alfa= ma->alpha; + har->r= ma->r; + har->g= ma->g; + har->b= ma->b; + har->add= (255.0f*ma->add); + har->mat= ma; + har->hard= ma->har; + har->seed= seed % 256; + + if (ma->mode & MA_STAR) har->starpoints= ma->starc; + if (ma->mode & MA_HALO_LINES) har->linec= ma->linec; + if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc; + if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec; + + if ((ma->mode & MA_HALOTEX) && ma->mtex[0]) + har->tex= 1; + + for (i=0; i<MAX_MTEX; i++) + if (ma->mtex[i] && (ma->septex & (1<<i))==0) { + mtex= ma->mtex[i]; + copy_v3_v3(texvec, vec); + + if (mtex->texco & TEXCO_NORM) { + ; + } + else if (mtex->texco & TEXCO_OBJECT) { + if (mtex->object) + mul_m4_v3(mtex->object->imat_ren, texvec); + } + else if (mtex->texco & TEXCO_GLOB) { + copy_v3_v3(texvec, vec); + } + else if (mtex->texco & TEXCO_UV && uvco) { + int uv_index=CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, mtex->uvname); + if (uv_index<0) + uv_index=CustomData_get_active_layer_index(&dm->faceData, CD_MTFACE); + + uv_index-=CustomData_get_layer_index(&dm->faceData, CD_MTFACE); + + texvec[0]=2.0f*uvco[2*uv_index]-1.0f; + texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f; + texvec[2]=0.0f; + } + else if (mtex->texco & TEXCO_PARTICLE) { + /* particle coordinates in range [0, 1] */ + texvec[0] = 2.f * pa_co[0] - 1.f; + texvec[1] = 2.f * pa_co[1] - 1.f; + texvec[2] = pa_co[2]; + } + else if (orco) { + copy_v3_v3(texvec, orco); + } + + hasrgb = externtex(mtex, + texvec, + &tin, &tr, &tg, &tb, &ta, + 0, + re->pool, + skip_load_image, + texnode_preview); + + //yn= tin*mtex->colfac; + //zn= tin*mtex->alphafac; + if (mtex->mapto & MAP_COL) { + tex[0]=tr; + tex[1]=tg; + tex[2]=tb; + out[0]=har->r; + out[1]=har->g; + out[2]=har->b; + + texture_rgb_blend(in, tex, out, tin, mtex->colfac, mtex->blendtype); + // zn= 1.0-yn; + //har->r= (yn*tr+ zn*ma->r); + //har->g= (yn*tg+ zn*ma->g); + //har->b= (yn*tb+ zn*ma->b); + har->r= in[0]; + har->g= in[1]; + har->b= in[2]; + } + + /* alpha returned, so let's use it instead of intensity */ + if (hasrgb) + tin = ta; + + if (mtex->mapto & MAP_ALPHA) + har->alfa = texture_value_blend(mtex->def_var, har->alfa, tin, mtex->alphafac, mtex->blendtype); + if (mtex->mapto & MAP_HAR) + har->hard = 1.0f+126.0f*texture_value_blend(mtex->def_var, ((float)har->hard)/127.0f, tin, mtex->hardfac, mtex->blendtype); + if (mtex->mapto & MAP_RAYMIRR) + har->hasize = 100.0f*texture_value_blend(mtex->def_var, har->hasize/100.0f, tin, mtex->raymirrfac, mtex->blendtype); + if (mtex->mapto & MAP_TRANSLU) { + float add = texture_value_blend(mtex->def_var, (float)har->add/255.0f, tin, mtex->translfac, mtex->blendtype); + CLAMP(add, 0.f, 1.f); + har->add = 255.0f*add; + } + /* now what on earth is this good for?? */ + //if (mtex->texco & 16) { + // har->alfa= tin; + //} + } + + har->pool = re->pool; + har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + + return har; +} + +/* -------------------------- operations on entire database ----------------------- */ + +/* ugly function for halos in panorama */ +static int panotestclip(Render *re, bool do_pano, float v[4]) +{ + /* part size (ensure we run RE_parts_clamp first) */ + BLI_assert(re->partx == min_ii(re->r.tilex, re->rectx)); + BLI_assert(re->party == min_ii(re->r.tiley, re->recty)); + + if (do_pano == false) { + return testclip(v); + } + else { + /* to be used for halos en infos */ + float abs4; + short c = 0; + + int xparts = (re->rectx + re->partx - 1) / re->partx; + + abs4= fabsf(v[3]); + + if (v[2]< -abs4) c=16; /* this used to be " if (v[2]<0) ", see clippz() */ + else if (v[2]> abs4) c+= 32; + + if ( v[1]>abs4) c+=4; + else if ( v[1]< -abs4) c+=8; + + abs4*= xparts; + if ( v[0]>abs4) c+=2; + else if ( v[0]< -abs4) c+=1; + + return c; + } +} + +/** + * This adds the hcs coordinates to vertices. It iterates over all + * vertices, halos and faces. After the conversion, we clip in hcs. + * + * Elsewhere, all primites are converted to vertices. + * Called in + * - envmapping (envmap.c) + * - shadow buffering (shadbuf.c) + */ + +void project_renderdata(Render *re, + void (*projectfunc)(const float *, float mat[4][4], float *), + bool do_pano, float xoffs, bool UNUSED(do_buckets)) +{ + ObjectRen *obr; + HaloRen *har = NULL; + float zn, vec[3], hoco[4]; + int a; + + if (do_pano) { + float panophi= xoffs; + + re->panosi = sinf(panophi); + re->panoco = cosf(panophi); + } + + for (obr=re->objecttable.first; obr; obr=obr->next) { + /* calculate view coordinates (and zbuffer value) */ + for (a=0; a<obr->tothalo; a++) { + if ((a & 255)==0) har= obr->bloha[a>>8]; + else har++; + + if (do_pano) { + vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2]; + vec[1]= har->co[1]; + vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2]; + } + else { + copy_v3_v3(vec, har->co); + } + + projectfunc(vec, re->winmat, hoco); + + /* we clip halos less critical, but not for the Z */ + hoco[0]*= 0.5f; + hoco[1]*= 0.5f; + + if ( panotestclip(re, do_pano, hoco) ) { + har->miny= har->maxy= -10000; /* that way render clips it */ + } + else if (hoco[3]<0.0f) { + har->miny= har->maxy= -10000; /* render clips it */ + } + else { /* do the projection...*/ + /* bring back hocos */ + hoco[0]*= 2.0f; + hoco[1]*= 2.0f; + + zn= hoco[3]; + har->xs= 0.5f*re->winx*(1.0f+hoco[0]/zn); /* the 0.5 negates the previous 2...*/ + har->ys= 0.5f*re->winy*(1.0f+hoco[1]/zn); + + /* this should be the zbuffer coordinate */ + har->zs= 0x7FFFFF*(hoco[2]/zn); + /* taking this from the face clip functions? seems ok... */ + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + vec[0]+= har->hasize; + projectfunc(vec, re->winmat, hoco); + vec[0]-= har->hasize; + zn= hoco[3]; + har->rad= fabsf(har->xs- 0.5f*re->winx*(1.0f+hoco[0]/zn)); + + /* this clip is not really OK, to prevent stars to become too large */ + if (har->type & HA_ONLYSKY) { + if (har->rad>3.0f) har->rad= 3.0f; + } + + har->radsq= har->rad*har->rad; + + har->miny= har->ys - har->rad/re->ycor; + har->maxy= har->ys + har->rad/re->ycor; + + /* the Zd value is still not really correct for pano */ + + vec[2] -= har->hasize; /* z negative, otherwise it's clipped */ + projectfunc(vec, re->winmat, hoco); + zn = hoco[3]; + zn = fabsf((float)har->zs - 0x7FFFFF * (hoco[2] / zn)); + har->zd = CLAMPIS(zn, 0, INT_MAX); + + } + + } + } +} + +/* ------------------------------------------------------------------------- */ + +void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag) +{ + /* flag specifies what things have changed. */ + if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) { + copy_m4_m4(obi->obmat, obi->ob->obmat); + invert_m4_m4(obi->obinvmat, obi->obmat); + } + if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) { + mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat); + mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv); + } +} + +void RE_updateRenderInstances(Render *re, int flag) +{ + int i = 0; + for (i = 0; i < re->totinstance; i++) + RE_updateRenderInstance(re, &re->objectinstance[i], flag); +} + +ObjectInstanceRen *RE_addRenderInstance( + Render *re, ObjectRen *obr, Object *ob, Object *par, + int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob) +{ + ObjectInstanceRen *obi; + float mat3[3][3]; + + obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen"); + obi->obr= obr; + obi->ob= ob; + obi->par= par; + obi->index= index; + obi->psysindex= psysindex; + obi->lay= lay; + + /* Fill particle info */ + if (par && dob) { + const ParticleSystem *psys = dob->particle_system; + if (psys) { + int part_index; + if (obi->index < psys->totpart) { + part_index = obi->index; + } + else if (psys->child) { + part_index = psys->child[obi->index - psys->totpart].parent; + } + else { + part_index = -1; + } + + if (part_index >= 0) { + const ParticleData *p = &psys->particles[part_index]; + obi->part_index = part_index; + obi->part_size = p->size; + obi->part_age = RE_GetStats(re)->cfra - p->time; + obi->part_lifetime = p->lifetime; + + copy_v3_v3(obi->part_co, p->state.co); + copy_v3_v3(obi->part_vel, p->state.vel); + copy_v3_v3(obi->part_avel, p->state.ave); + } + } + } + + /* Fill object info */ + if (dob) { + obi->random_id = dob->random_id; + } + else { + obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0); + } + + RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW); + + if (mat) { + copy_m4_m4(obi->mat, mat); + copy_m3_m4(mat3, mat); + invert_m3_m3(obi->nmat, mat3); + transpose_m3(obi->nmat); + obi->flag |= R_DUPLI_TRANSFORMED; + } + + BLI_addtail(&re->instancetable, obi); + + return obi; +} + +void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) +{ + *index = obi->part_index; + *random = BLI_hash_int_01(obi->part_index); + *age = obi->part_age; + *lifetime = obi->part_lifetime; + copy_v3_v3(co, obi->part_co); + *size = obi->part_size; + copy_v3_v3(vel, obi->part_vel); + copy_v3_v3(angvel, obi->part_avel); +} + + +void RE_makeRenderInstances(Render *re) +{ + ObjectInstanceRen *obi, *oldobi; + ListBase newlist; + int tot; + + /* convert list of object instances to an array for index based lookup */ + tot= BLI_listbase_count(&re->instancetable); + re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance"); + re->totinstance= tot; + newlist.first= newlist.last= NULL; + + obi= re->objectinstance; + for (oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) { + *obi= *oldobi; + + if (obi->obr) { + obi->prev= obi->next= NULL; + BLI_addtail(&newlist, obi); + obi++; + } + else + re->totinstance--; + } + + BLI_freelistN(&re->instancetable); + re->instancetable= newlist; +} + +/* four functions to facilitate envmap rotation for raytrace */ +void RE_instance_rotate_ray_start(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + copy_v3_v3(is->origstart, is->start); + mul_m4_v3(obi->imat, is->start); + } +} + +void RE_instance_rotate_ray_dir(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + float end[3]; + + copy_v3_v3(is->origdir, is->dir); + add_v3_v3v3(end, is->origstart, is->dir); + + mul_m4_v3(obi->imat, end); + sub_v3_v3v3(is->dir, end, is->start); + } +} + +void RE_instance_rotate_ray(ObjectInstanceRen *obi, Isect *is) +{ + RE_instance_rotate_ray_start(obi, is); + RE_instance_rotate_ray_dir(obi, is); +} + +void RE_instance_rotate_ray_restore(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + copy_v3_v3(is->start, is->origstart); + copy_v3_v3(is->dir, is->origdir); + } +} + +int clip_render_object(float boundbox[2][3], float bounds[4], float winmat[4][4]) +{ + float mat[4][4], vec[4]; + int a, fl, flag = -1; + + copy_m4_m4(mat, winmat); + + for (a=0; a < 8; a++) { + vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0]; + vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1]; + vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2]; + vec[3]= 1.0; + mul_m4_v4(mat, vec); + + fl = 0; + if (bounds) { + if (vec[0] < bounds[0] * vec[3]) fl |= 1; + else if (vec[0] > bounds[1] * vec[3]) fl |= 2; + + if (vec[1] > bounds[3] * vec[3]) fl |= 4; + else if (vec[1] < bounds[2] * vec[3]) fl |= 8; + } + else { + if (vec[0] < -vec[3]) fl |= 1; + else if (vec[0] > vec[3]) fl |= 2; + + if (vec[1] > vec[3]) fl |= 4; + else if (vec[1] < -vec[3]) fl |= 8; + } + if (vec[2] < -vec[3]) fl |= 16; + else if (vec[2] > vec[3]) fl |= 32; + + flag &= fl; + if (flag == 0) { + return 0; + } + } + + return flag; +} + |