Bug fix: Halos didn't use texture alpha
[blender-staging.git] / source / blender / render / intern / source / renderdatabase.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): 2004-2006, Blender Foundation, full recode
24  *
25  * ***** END GPL/BL DUAL LICENSE BLOCK *****
26  */
27
28 /*
29  * Storage, retrieval and query of render specific data.
30  *
31  * All data from a Blender scene is converted by the renderconverter/
32  * into a special format that is used by the render module to make
33  * images out of. These functions interface to the render-specific
34  * database.  
35  *
36  * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data
37  * entries each.
38  *
39  * The index of an entry is >>8 (the highest 24 * bits), to find an
40  * offset in a 256-entry block.
41  *
42  * - If the 256-entry block entry has an entry in the
43  * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in
44  * that block is allocated to this entry.
45  *
46  * - If the entry has no block allocated for it yet, memory is
47  * allocated.
48  *
49  * The pointer to the correct entry is returned. Memory is guarateed
50  * to exist (as long as the malloc does not break). Since guarded
51  * allocation is used, memory _must_ be available. Otherwise, an
52  * exit(0) would occur.
53  * 
54  */
55
56 #include <limits.h>
57 #include <math.h>
58 #include <string.h>
59
60 #include "MEM_guardedalloc.h"
61 #include "BKE_utildefines.h"
62
63 #include "BLI_math.h"
64 #include "BLI_blenlib.h"
65 #include "BLI_ghash.h"
66 #include "BLI_memarena.h"
67
68 #include "DNA_material_types.h" 
69 #include "DNA_mesh_types.h" 
70 #include "DNA_meshdata_types.h" 
71 #include "DNA_texture_types.h" 
72
73 #include "BKE_customdata.h"
74 #include "BKE_texture.h" 
75 #include "BKE_DerivedMesh.h"
76
77 #include "RE_render_ext.h"      /* externtex */
78 #include "RE_raytrace.h"
79
80 #include "renderpipeline.h"
81 #include "render_types.h"
82 #include "renderdatabase.h"
83 #include "texture.h"
84 #include "strand.h"
85 #include "zbuf.h"
86
87 /* ------------------------------------------------------------------------- */
88
89 /* More dynamic allocation of options for render vertices and faces, so we dont
90    have to reserve this space inside vertices.
91    Important; vertices and faces, should have been created already (to get tables
92    checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
93    the index */
94
95 /* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
96
97 #define RE_STICKY_ELEMS         2
98 #define RE_STRESS_ELEMS         1
99 #define RE_RAD_ELEMS            4
100 #define RE_STRAND_ELEMS         1
101 #define RE_TANGENT_ELEMS        3
102 #define RE_STRESS_ELEMS         1
103 #define RE_WINSPEED_ELEMS       4
104 #define RE_MTFACE_ELEMS         1
105 #define RE_MCOL_ELEMS           4
106 #define RE_UV_ELEMS                     2
107 #define RE_SURFNOR_ELEMS        3
108 #define RE_RADFACE_ELEMS        1
109 #define RE_SIMPLIFY_ELEMS       2
110 #define RE_FACE_ELEMS           1
111 #define RE_NMAP_TANGENT_ELEMS   12
112
113 float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify)
114 {
115         float *sticky;
116         int nr= ver->index>>8;
117         
118         sticky= obr->vertnodes[nr].sticky;
119         if(sticky==NULL) {
120                 if(verify) 
121                         sticky= obr->vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table");
122                 else
123                         return NULL;
124         }
125         return sticky + (ver->index & 255)*RE_STICKY_ELEMS;
126 }
127
128 float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify)
129 {
130         float *stress;
131         int nr= ver->index>>8;
132         
133         stress= obr->vertnodes[nr].stress;
134         if(stress==NULL) {
135                 if(verify) 
136                         stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
137                 else
138                         return NULL;
139         }
140         return stress + (ver->index & 255)*RE_STRESS_ELEMS;
141 }
142
143 /* this one callocs! */
144 float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify)
145 {
146         float *rad;
147         int nr= ver->index>>8;
148         
149         rad= obr->vertnodes[nr].rad;
150         if(rad==NULL) {
151                 if(verify) 
152                         rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
153                 else
154                         return NULL;
155         }
156         return rad + (ver->index & 255)*RE_RAD_ELEMS;
157 }
158
159 float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify)
160 {
161         float *strand;
162         int nr= ver->index>>8;
163         
164         strand= obr->vertnodes[nr].strand;
165         if(strand==NULL) {
166                 if(verify) 
167                         strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
168                 else
169                         return NULL;
170         }
171         return strand + (ver->index & 255)*RE_STRAND_ELEMS;
172 }
173
174 /* needs calloc */
175 float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify)
176 {
177         float *tangent;
178         int nr= ver->index>>8;
179         
180         tangent= obr->vertnodes[nr].tangent;
181         if(tangent==NULL) {
182                 if(verify) 
183                         tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
184                 else
185                         return NULL;
186         }
187         return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
188 }
189
190 /* needs calloc! not all renderverts have them */
191 /* also winspeed is exception, it is stored per instance */
192 float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify)
193 {
194         float *winspeed;
195         int totvector;
196         
197         winspeed= obi->vectors;
198         if(winspeed==NULL) {
199                 if(verify) {
200                         totvector= obi->obr->totvert + obi->obr->totstrand;
201                         winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
202                 }
203                 else
204                         return NULL;
205         }
206         return winspeed + ver->index*RE_WINSPEED_ELEMS;
207 }
208
209 VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
210 {
211         VertRen *v1= RE_findOrAddVert(obr, obr->totvert++);
212         float *fp1, *fp2;
213         int index= v1->index;
214         
215         *v1= *ver;
216         v1->index= index;
217         
218         fp1= RE_vertren_get_sticky(obr, ver, 0);
219         if(fp1) {
220                 fp2= RE_vertren_get_sticky(obr, v1, 1);
221                 memcpy(fp2, fp1, RE_STICKY_ELEMS*sizeof(float));
222         }
223         fp1= RE_vertren_get_stress(obr, ver, 0);
224         if(fp1) {
225                 fp2= RE_vertren_get_stress(obr, v1, 1);
226                 memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
227         }
228         fp1= RE_vertren_get_rad(obr, ver, 0);
229         if(fp1) {
230                 fp2= RE_vertren_get_rad(obr, v1, 1);
231                 memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
232         }
233         fp1= RE_vertren_get_strand(obr, ver, 0);
234         if(fp1) {
235                 fp2= RE_vertren_get_strand(obr, v1, 1);
236                 memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
237         }
238         fp1= RE_vertren_get_tangent(obr, ver, 0);
239         if(fp1) {
240                 fp2= RE_vertren_get_tangent(obr, v1, 1);
241                 memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
242         }
243         return v1;
244 }
245
246 VertRen *RE_findOrAddVert(ObjectRen *obr, int nr)
247 {
248         VertTableNode *temp;
249         VertRen *v;
250         int a;
251
252         if(nr<0) {
253                 printf("error in findOrAddVert: %d\n",nr);
254                 return NULL;
255         }
256         a= nr>>8;
257         
258         if (a>=obr->vertnodeslen-1) {  /* Need to allocate more columns..., and keep last element NULL for free loop */
259                 temp= obr->vertnodes;
260                 
261                 obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE) , "vertnodes");
262                 if(temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode));
263                 memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
264                 
265                 obr->vertnodeslen+=TABLEINITSIZE; 
266                 if(temp) MEM_freeN(temp);       
267         }
268         
269         v= obr->vertnodes[a].vert;
270         if(v==NULL) {
271                 int i;
272                 
273                 v= (VertRen *)MEM_callocN(256*sizeof(VertRen),"findOrAddVert");
274                 obr->vertnodes[a].vert= v;
275                 
276                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
277                         v[a].index= i;
278                 }
279         }
280         v+= (nr & 255);
281         return v;
282 }
283
284 /* ------------------------------------------------------------------------ */
285
286 MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
287 {
288         VlakTableNode *node;
289         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
290         int index= (n<<8) + vlakindex;
291
292         node= &obr->vlaknodes[nr];
293
294         if(verify) {
295                 if(n>=node->totmtface) {
296                         MTFace *mtface= node->mtface;
297                         int size= size= (n+1)*256;
298
299                         node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface");
300
301                         if(mtface) {
302                                 size= node->totmtface*256;
303                                 memcpy(node->mtface, mtface, size*sizeof(MTFace));
304                                 MEM_freeN(mtface);
305                         }
306
307                         node->totmtface= n+1;
308                 }
309         }
310         else {
311                 if(n>=node->totmtface)
312                         return NULL;
313
314                 if(name) *name= obr->mtface[n];
315         }
316
317         return node->mtface + index;
318 }
319
320 MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
321 {
322         VlakTableNode *node;
323         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
324         int index= (n<<8) + vlakindex;
325
326         node= &obr->vlaknodes[nr];
327
328         if(verify) {
329                 if(n>=node->totmcol) {
330                         MCol *mcol= node->mcol;
331                         int size= (n+1)*256;
332
333                         node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol");
334
335                         if(mcol) {
336                                 size= node->totmcol*256;
337                                 memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
338                                 MEM_freeN(mcol);
339                         }
340
341                         node->totmcol= n+1;
342                 }
343         }
344         else {
345                 if(n>=node->totmcol)
346                         return NULL;
347
348                 if(name) *name= obr->mcol[n];
349         }
350
351         return node->mcol + index*RE_MCOL_ELEMS;
352 }
353
354 float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
355 {
356         float *surfnor;
357         int nr= vlak->index>>8;
358         
359         surfnor= obr->vlaknodes[nr].surfnor;
360         if(surfnor==NULL) {
361                 if(verify) 
362                         surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
363                 else
364                         return NULL;
365         }
366         return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
367 }
368
369 float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int verify)
370 {
371         float *tangent;
372         int nr= vlak->index>>8;
373
374         tangent= obr->vlaknodes[nr].tangent;
375         if(tangent==NULL) {
376                 if(verify) 
377                         tangent= obr->vlaknodes[nr].tangent= MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
378                 else
379                         return NULL;
380         }
381         return tangent + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
382 }
383
384 RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
385 {
386         RadFace **radface;
387         int nr= vlak->index>>8;
388         
389         radface= obr->vlaknodes[nr].radface;
390         if(radface==NULL) {
391                 if(verify) 
392                         radface= obr->vlaknodes[nr].radface= MEM_callocN(256*RE_RADFACE_ELEMS*sizeof(void*), "radface table");
393                 else
394                         return NULL;
395         }
396         return radface + (vlak->index & 255)*RE_RADFACE_ELEMS;
397 }
398
399 VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
400 {
401         VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
402         MTFace *mtface, *mtface1;
403         MCol *mcol, *mcol1;
404         float *surfnor, *surfnor1, *tangent, *tangent1;
405         RadFace **radface, **radface1;
406         int i, index = vlr1->index;
407         char *name;
408
409         *vlr1= *vlr;
410         vlr1->index= index;
411
412         for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) {
413                 mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1);
414                 memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
415         }
416
417         for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) {
418                 mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1);
419                 memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
420         }
421
422         surfnor= RE_vlakren_get_surfnor(obr, vlr, 0);
423         if(surfnor) {
424                 surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1);
425                 VECCOPY(surfnor1, surfnor);
426         }
427
428         tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0);
429         if(tangent) {
430                 tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1);
431                 memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
432         }
433
434         radface= RE_vlakren_get_radface(obr, vlr, 0);
435         if(radface) {
436                 radface1= RE_vlakren_get_radface(obr, vlr1, 1);
437                 *radface1= *radface;
438         }
439
440         return vlr1;
441 }
442
443 void RE_vlakren_get_normal(Render *re, ObjectInstanceRen *obi, VlakRen *vlr, float *nor)
444 {
445         float (*nmat)[3]= obi->nmat;
446
447         if(obi->flag & R_TRANSFORMED) {
448                 VECCOPY(nor, vlr->n);
449                 
450                 mul_m3_v3(nmat, nor);
451                 normalize_v3(nor);
452         }
453         else
454                 VECCOPY(nor, vlr->n);
455 }
456
457 void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
458 {
459         /* CustomData layer names are stored per object here, because the
460            DerivedMesh which stores the layers is freed */
461         
462         CustomDataLayer *layer;
463         int numtf = 0, numcol = 0, i, mtfn, mcn;
464
465         if (CustomData_has_layer(data, CD_MTFACE)) {
466                 numtf= CustomData_number_of_layers(data, CD_MTFACE);
467                 obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames");
468         }
469
470         if (CustomData_has_layer(data, CD_MCOL)) {
471                 numcol= CustomData_number_of_layers(data, CD_MCOL);
472                 obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames");
473         }
474
475         for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
476                 layer= &data->layers[i];
477
478                 if (layer->type == CD_MTFACE) {
479                         strcpy(obr->mtface[mtfn++], layer->name);
480                         obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf);
481                         obr->bakemtface= layer->active;
482                 }
483                 else if (layer->type == CD_MCOL) {
484                         strcpy(obr->mcol[mcn++], layer->name);
485                         obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol);
486                 }
487         }
488 }
489
490 VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr)
491 {
492         VlakTableNode *temp;
493         VlakRen *v;
494         int a;
495
496         if(nr<0) {
497                 printf("error in findOrAddVlak: %d\n",nr);
498                 return obr->vlaknodes[0].vlak;
499         }
500         a= nr>>8;
501         
502         if (a>=obr->vlaknodeslen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
503                 temp= obr->vlaknodes;
504                 
505                 obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE) , "vlaknodes");
506                 if(temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode));
507                 memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
508
509                 obr->vlaknodeslen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
510                 if(temp) MEM_freeN(temp);       
511         }
512
513         v= obr->vlaknodes[a].vlak;
514         
515         if(v==NULL) {
516                 int i;
517
518                 v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen),"findOrAddVlak");
519                 obr->vlaknodes[a].vlak= v;
520
521                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
522                         v[a].index= i;
523         }
524         v+= (nr & 255);
525         return v;
526 }
527
528 /* ------------------------------------------------------------------------ */
529
530 float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify)
531 {
532         float *surfnor;
533         int nr= strand->index>>8;
534         
535         surfnor= obr->strandnodes[nr].surfnor;
536         if(surfnor==NULL) {
537                 if(verify) 
538                         surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table");
539                 else
540                         return NULL;
541         }
542         return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
543 }
544
545 float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
546 {
547         StrandTableNode *node;
548         int nr= strand->index>>8, strandindex= (strand->index&255);
549         int index= (n<<8) + strandindex;
550
551         node= &obr->strandnodes[nr];
552
553         if(verify) {
554                 if(n>=node->totuv) {
555                         float *uv= node->uv;
556                         int size= (n+1)*256;
557
558                         node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table");
559
560                         if(uv) {
561                                 size= node->totuv*256;
562                                 memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS);
563                                 MEM_freeN(uv);
564                         }
565
566                         node->totuv= n+1;
567                 }
568         }
569         else {
570                 if(n>=node->totuv)
571                         return NULL;
572
573                 if(name) *name= obr->mtface[n];
574         }
575
576         return node->uv + index*RE_UV_ELEMS;
577 }
578
579 MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
580 {
581         StrandTableNode *node;
582         int nr= strand->index>>8, strandindex= (strand->index&255);
583         int index= (n<<8) + strandindex;
584
585         node= &obr->strandnodes[nr];
586
587         if(verify) {
588                 if(n>=node->totmcol) {
589                         MCol *mcol= node->mcol;
590                         int size= (n+1)*256;
591
592                         node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table");
593
594                         if(mcol) {
595                                 size= node->totmcol*256;
596                                 memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
597                                 MEM_freeN(mcol);
598                         }
599
600                         node->totmcol= n+1;
601                 }
602         }
603         else {
604                 if(n>=node->totmcol)
605                         return NULL;
606
607                 if(name) *name= obr->mcol[n];
608         }
609
610         return node->mcol + index*RE_MCOL_ELEMS;
611 }
612
613 float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify)
614 {
615         float *simplify;
616         int nr= strand->index>>8;
617         
618         simplify= obr->strandnodes[nr].simplify;
619         if(simplify==NULL) {
620                 if(verify) 
621                         simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table");
622                 else
623                         return NULL;
624         }
625         return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
626 }
627
628 int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify)
629 {
630         int *face;
631         int nr= strand->index>>8;
632         
633         face= obr->strandnodes[nr].face;
634         if(face==NULL) {
635                 if(verify) 
636                         face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table");
637                 else
638                         return NULL;
639         }
640         return face + (strand->index & 255)*RE_FACE_ELEMS;
641 }
642
643 /* winspeed is exception, it is stored per instance */
644 float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
645 {
646         float *winspeed;
647         int totvector;
648         
649         winspeed= obi->vectors;
650         if(winspeed==NULL) {
651                 if(verify) {
652                         totvector= obi->obr->totvert + obi->obr->totstrand;
653                         winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table");
654                 }
655                 else
656                         return NULL;
657         }
658         return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS;
659 }
660
661 StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr)
662 {
663         StrandTableNode *temp;
664         StrandRen *v;
665         int a;
666
667         if(nr<0) {
668                 printf("error in findOrAddStrand: %d\n",nr);
669                 return obr->strandnodes[0].strand;
670         }
671         a= nr>>8;
672         
673         if (a>=obr->strandnodeslen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
674                 temp= obr->strandnodes;
675                 
676                 obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE) , "strandnodes");
677                 if(temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode));
678                 memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
679
680                 obr->strandnodeslen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
681                 if(temp) MEM_freeN(temp);       
682         }
683
684         v= obr->strandnodes[a].strand;
685         
686         if(v==NULL) {
687                 int i;
688
689                 v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen),"findOrAddStrand");
690                 obr->strandnodes[a].strand= v;
691
692                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
693                         v[a].index= i;
694         }
695         v+= (nr & 255);
696         return v;
697 }
698
699 StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
700 {
701         StrandBuffer *strandbuf;
702
703         strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
704         strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
705         strandbuf->totvert= totvert;
706         strandbuf->obr= obr;
707
708         obr->strandbuf= strandbuf;
709
710         return strandbuf;
711 }
712
713 /* ------------------------------------------------------------------------ */
714
715 ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay)
716 {
717         ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct");
718         
719         BLI_addtail(&re->objecttable, obr);
720         obr->ob= ob;
721         obr->par= par;
722         obr->index= index;
723         obr->psysindex= psysindex;
724         obr->lay= lay;
725
726         return obr;
727 }
728
729 void free_renderdata_vertnodes(VertTableNode *vertnodes)
730 {
731         int a;
732         
733         if(vertnodes==NULL) return;
734         
735         for(a=0; vertnodes[a].vert; a++) {
736                 MEM_freeN(vertnodes[a].vert);
737                 
738                 if(vertnodes[a].rad)
739                         MEM_freeN(vertnodes[a].rad);
740                 if(vertnodes[a].sticky)
741                         MEM_freeN(vertnodes[a].sticky);
742                 if(vertnodes[a].strand)
743                         MEM_freeN(vertnodes[a].strand);
744                 if(vertnodes[a].tangent)
745                         MEM_freeN(vertnodes[a].tangent);
746                 if(vertnodes[a].stress)
747                         MEM_freeN(vertnodes[a].stress);
748                 if(vertnodes[a].winspeed)
749                         MEM_freeN(vertnodes[a].winspeed);
750         }
751         
752         MEM_freeN(vertnodes);
753 }
754
755 void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
756 {
757         int a;
758         
759         if(vlaknodes==NULL) return;
760         
761         for(a=0; vlaknodes[a].vlak; a++) {
762                 MEM_freeN(vlaknodes[a].vlak);
763                 
764                 if(vlaknodes[a].mtface)
765                         MEM_freeN(vlaknodes[a].mtface);
766                 if(vlaknodes[a].mcol)
767                         MEM_freeN(vlaknodes[a].mcol);
768                 if(vlaknodes[a].surfnor)
769                         MEM_freeN(vlaknodes[a].surfnor);
770                 if(vlaknodes[a].tangent)
771                         MEM_freeN(vlaknodes[a].tangent);
772                 if(vlaknodes[a].radface)
773                         MEM_freeN(vlaknodes[a].radface);
774         }
775         
776         MEM_freeN(vlaknodes);
777 }
778
779 void free_renderdata_strandnodes(StrandTableNode *strandnodes)
780 {
781         int a;
782         
783         if(strandnodes==NULL) return;
784         
785         for(a=0; strandnodes[a].strand; a++) {
786                 MEM_freeN(strandnodes[a].strand);
787                 
788                 if(strandnodes[a].uv)
789                         MEM_freeN(strandnodes[a].uv);
790                 if(strandnodes[a].mcol)
791                         MEM_freeN(strandnodes[a].mcol);
792                 if(strandnodes[a].winspeed)
793                         MEM_freeN(strandnodes[a].winspeed);
794                 if(strandnodes[a].surfnor)
795                         MEM_freeN(strandnodes[a].surfnor);
796                 if(strandnodes[a].simplify)
797                         MEM_freeN(strandnodes[a].simplify);
798                 if(strandnodes[a].face)
799                         MEM_freeN(strandnodes[a].face);
800         }
801         
802         MEM_freeN(strandnodes);
803 }
804
805 void free_renderdata_tables(Render *re)
806 {
807         ObjectInstanceRen *obi;
808         ObjectRen *obr;
809         StrandBuffer *strandbuf;
810         int a=0;
811         
812         for(obr=re->objecttable.first; obr; obr=obr->next) {
813                 if(obr->vertnodes) {
814                         free_renderdata_vertnodes(obr->vertnodes);
815                         obr->vertnodes= NULL;
816                         obr->vertnodeslen= 0;
817                 }
818
819                 if(obr->vlaknodes) {
820                         free_renderdata_vlaknodes(obr->vlaknodes);
821                         obr->vlaknodes= NULL;
822                         obr->vlaknodeslen= 0;
823                         obr->totvlak= 0;
824                 }
825
826                 if(obr->bloha) {
827                         for(a=0; obr->bloha[a]; a++)
828                                 MEM_freeN(obr->bloha[a]);
829
830                         MEM_freeN(obr->bloha);
831                         obr->bloha= NULL;
832                         obr->blohalen= 0;
833                 }
834
835                 if(obr->strandnodes) {
836                         free_renderdata_strandnodes(obr->strandnodes);
837                         obr->strandnodes= NULL;
838                         obr->strandnodeslen= 0;
839                 }
840
841                 strandbuf= obr->strandbuf;
842                 if(strandbuf) {
843                         if(strandbuf->vert) MEM_freeN(strandbuf->vert);
844                         if(strandbuf->bound) MEM_freeN(strandbuf->bound);
845                         MEM_freeN(strandbuf);
846                 }
847
848                 if(obr->mtface)
849                         MEM_freeN(obr->mtface);
850                 if(obr->mcol)
851                         MEM_freeN(obr->mcol);
852                         
853                 if(obr->rayfaces)
854                 {
855                         MEM_freeN(obr->rayfaces);
856                         obr->rayfaces = NULL;
857                 }
858                 if(obr->rayprimitives)
859                 {
860                         MEM_freeN(obr->rayprimitives);
861                         obr->rayprimitives = NULL;
862                 }
863                 if(obr->raytree)
864                 {
865                         RE_rayobject_free(obr->raytree);
866                         obr->raytree = NULL;
867                 }
868         }
869
870         if(re->objectinstance) {
871                 for(obi=re->instancetable.first; obi; obi=obi->next)
872                 {
873                         if(obi->vectors)
874                                 MEM_freeN(obi->vectors);
875
876                         if(obi->raytree)
877                                 RE_rayobject_free(obi->raytree);
878                 }
879
880                 MEM_freeN(re->objectinstance);
881                 re->objectinstance= NULL;
882                 re->totinstance= 0;
883                 re->instancetable.first= re->instancetable.last= NULL;
884         }
885
886         if(re->sortedhalos) {
887                 MEM_freeN(re->sortedhalos);
888                 re->sortedhalos= NULL;
889         }
890
891         BLI_freelistN(&re->customdata_names);
892         BLI_freelistN(&re->objecttable);
893         BLI_freelistN(&re->instancetable);
894 }
895
896 /* ------------------------------------------------------------------------ */
897
898 HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr)
899 {
900         HaloRen *h, **temp;
901         int a;
902
903         if(nr<0) {
904                 printf("error in findOrAddHalo: %d\n",nr);
905                 return NULL;
906         }
907         a= nr>>8;
908         
909         if (a>=obr->blohalen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
910                 //printf("Allocating %i more halo groups.  %i total.\n", 
911                 //      TABLEINITSIZE, obr->blohalen+TABLEINITSIZE );
912                 temp=obr->bloha;
913                 
914                 obr->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(obr->blohalen+TABLEINITSIZE) , "Bloha");
915                 if(temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void*));
916                 memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE*sizeof(void*));
917                 obr->blohalen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
918                 if(temp) MEM_freeN(temp);       
919         }
920         
921         h= obr->bloha[a];
922         if(h==NULL) {
923                 h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen),"findOrAdHalo");
924                 obr->bloha[a]= h;
925         }
926         h+= (nr & 255);
927         return h;
928 }
929
930 /* ------------------------------------------------------------------------- */
931
932 HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,   float *vec,   float *vec1, 
933                                   float *orco,   float hasize,   float vectsize, int seed)
934 {
935         HaloRen *har;
936         MTex *mtex;
937         float tin, tr, tg, tb, ta;
938         float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
939
940         if(hasize==0.0) return NULL;
941
942         projectverto(vec, re->winmat, hoco);
943         if(hoco[3]==0.0) return NULL;
944         if(vec1) {
945                 projectverto(vec1, re->winmat, hoco1);
946                 if(hoco1[3]==0.0) return NULL;
947         }
948
949         har= RE_findOrAddHalo(obr, obr->tothalo++);
950         VECCOPY(har->co, vec);
951         har->hasize= hasize;
952
953         /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
954         /* we do it here for sorting of halos */
955         zn= hoco[3];
956         har->xs= 0.5*re->winx*(hoco[0]/zn);
957         har->ys= 0.5*re->winy*(hoco[1]/zn);
958         har->zs= 0x7FFFFF*(hoco[2]/zn);
959         
960         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); 
961         
962         /* halovect */
963         if(vec1) {
964
965                 har->type |= HA_VECT;
966
967                 xn=  har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
968                 yn=  har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
969                 if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
970                 else zn= atan2(yn, xn);
971
972                 har->sin= sin(zn);
973                 har->cos= cos(zn);
974                 zn= len_v3v3(vec1, vec);
975
976                 har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
977                 
978                 sub_v3_v3v3(har->no, vec, vec1);
979                 normalize_v3(har->no);
980         }
981
982         if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
983
984         har->alfa= ma->alpha;
985         har->r= ma->r;
986         har->g= ma->g;
987         har->b= ma->b;
988         har->add= (255.0*ma->add);
989         har->mat= ma;
990         har->hard= ma->har;
991         har->seed= seed % 256;
992
993         if(ma->mode & MA_STAR) har->starpoints= ma->starc;
994         if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
995         if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
996         if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
997
998
999         if(ma->mtex[0]) {
1000
1001                 if( (ma->mode & MA_HALOTEX) ) har->tex= 1;
1002                 else {
1003
1004                         mtex= ma->mtex[0];
1005                         VECCOPY(texvec, vec);
1006
1007                         if(mtex->texco & TEXCO_NORM) {
1008                                 ;
1009                         }
1010                         else if(mtex->texco & TEXCO_OBJECT) {
1011                                 /* texvec[0]+= imatbase->ivec[0]; */
1012                                 /* texvec[1]+= imatbase->ivec[1]; */
1013                                 /* texvec[2]+= imatbase->ivec[2]; */
1014                                 /* mul_m3_v3(imatbase->imat, texvec); */
1015                         }
1016                         else {
1017                                 if(orco) {
1018                                         VECCOPY(texvec, orco);
1019                                 }
1020                         }
1021
1022                         externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0);
1023
1024                         yn= tin*mtex->colfac;
1025                         zn= tin*mtex->alphafac;
1026
1027                         if(mtex->mapto & MAP_COL) {
1028                                 zn= 1.0-yn;
1029                                 har->r= (yn*tr+ zn*ma->r);
1030                                 har->g= (yn*tg+ zn*ma->g);
1031                                 har->b= (yn*tb+ zn*ma->b);
1032                         }
1033                         if(mtex->texco & TEXCO_UV) {
1034                                 har->alfa= tin;
1035                         }
1036                         if(mtex->mapto & MAP_ALPHA)
1037                                 har->alfa= tin;
1038                 }
1039         }
1040
1041         return har;
1042 }
1043
1044 HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma,   float *vec,   float *vec1, 
1045                                   float *orco, float *uvco, float hasize, float vectsize, int seed)
1046 {
1047         HaloRen *har;
1048         MTex *mtex;
1049         float tin, tr, tg, tb, ta;
1050         float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3],tex[3],out[3];
1051         int i, hasrgb;
1052
1053         if(hasize==0.0) return NULL;
1054
1055         projectverto(vec, re->winmat, hoco);
1056         if(hoco[3]==0.0) return NULL;
1057         if(vec1) {
1058                 projectverto(vec1, re->winmat, hoco1);
1059                 if(hoco1[3]==0.0) return NULL;
1060         }
1061
1062         har= RE_findOrAddHalo(obr, obr->tothalo++);
1063         VECCOPY(har->co, vec);
1064         har->hasize= hasize;
1065
1066         /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
1067         /* we do it here for sorting of halos */
1068         zn= hoco[3];
1069         har->xs= 0.5*re->winx*(hoco[0]/zn);
1070         har->ys= 0.5*re->winy*(hoco[1]/zn);
1071         har->zs= 0x7FFFFF*(hoco[2]/zn);
1072         
1073         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); 
1074         
1075         /* halovect */
1076         if(vec1) {
1077
1078                 har->type |= HA_VECT;
1079
1080                 xn=  har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
1081                 yn=  har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
1082                 if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
1083                 else zn= atan2(yn, xn);
1084
1085                 har->sin= sin(zn);
1086                 har->cos= cos(zn);
1087                 zn= len_v3v3(vec1, vec)*0.5;
1088
1089                 har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
1090                 
1091                 sub_v3_v3v3(har->no, vec, vec1);
1092                 normalize_v3(har->no);
1093         }
1094
1095         if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
1096
1097         har->alfa= ma->alpha;
1098         har->r= ma->r;
1099         har->g= ma->g;
1100         har->b= ma->b;
1101         har->add= (255.0*ma->add);
1102         har->mat= ma;
1103         har->hard= ma->har;
1104         har->seed= seed % 256;
1105
1106         if(ma->mode & MA_STAR) har->starpoints= ma->starc;
1107         if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
1108         if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
1109         if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
1110
1111         if((ma->mode & MA_HALOTEX) && ma->mtex[0]){
1112                 har->tex= 1;
1113                 i=1;
1114         }
1115         
1116         for(i=0; i<MAX_MTEX; i++)
1117                 if(ma->mtex[i] && (ma->septex & (1<<i))==0) {
1118                         mtex= ma->mtex[i];
1119                         VECCOPY(texvec, vec);
1120
1121                         if(mtex->texco & TEXCO_NORM) {
1122                                 ;
1123                         }
1124                         else if(mtex->texco & TEXCO_OBJECT) {
1125                                 if(mtex->object){
1126                                         float imat[4][4];
1127                                         /* imat should really be cached somewhere before this */
1128                                         invert_m4_m4(imat,mtex->object->obmat);
1129                                         mul_m4_v3(imat,texvec);
1130                                 }
1131                                 /* texvec[0]+= imatbase->ivec[0]; */
1132                                 /* texvec[1]+= imatbase->ivec[1]; */
1133                                 /* texvec[2]+= imatbase->ivec[2]; */
1134                                 /* mul_m3_v3(imatbase->imat, texvec); */
1135                         }
1136                         else if(mtex->texco & TEXCO_GLOB){
1137                                 VECCOPY(texvec,vec);
1138                         }
1139                         else if(mtex->texco & TEXCO_UV && uvco){
1140                                 int uv_index=CustomData_get_named_layer_index(&dm->faceData,CD_MTFACE,mtex->uvname);
1141                                 if(uv_index<0)
1142                                         uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE);
1143
1144                                 uv_index-=CustomData_get_layer_index(&dm->faceData,CD_MTFACE);
1145
1146                                 texvec[0]=2.0f*uvco[2*uv_index]-1.0f;
1147                                 texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f;
1148                                 texvec[2]=0.0f;
1149                         }
1150                         else if(orco) {
1151                                 VECCOPY(texvec, orco);
1152                         }
1153
1154                         hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0);
1155
1156                         //yn= tin*mtex->colfac;
1157                         //zn= tin*mtex->alphafac;
1158                         if(mtex->mapto & MAP_COL) {
1159                                 tex[0]=tr;
1160                                 tex[1]=tg;
1161                                 tex[2]=tb;
1162                                 out[0]=har->r;
1163                                 out[1]=har->g;
1164                                 out[2]=har->b;
1165
1166                                 texture_rgb_blend(in,tex,out,tin,mtex->colfac,mtex->blendtype);
1167                         //      zn= 1.0-yn;
1168                                 //har->r= (yn*tr+ zn*ma->r);
1169                                 //har->g= (yn*tg+ zn*ma->g);
1170                                 //har->b= (yn*tb+ zn*ma->b);
1171                                 har->r= in[0];
1172                                 har->g= in[1];
1173                                 har->b= in[2];
1174                         }
1175
1176                         /* alpha returned, so let's use it instead of intensity */
1177                         if(hasrgb)
1178                                 tin = ta;
1179
1180                         if(mtex->mapto & MAP_ALPHA)
1181                                 har->alfa = texture_value_blend(mtex->def_var,har->alfa,tin,mtex->alphafac,mtex->blendtype);
1182                         if(mtex->mapto & MAP_HAR)
1183                                 har->hard = 1.0+126.0*texture_value_blend(mtex->def_var,((float)har->hard)/127.0,tin,mtex->hardfac,mtex->blendtype);
1184                         if(mtex->mapto & MAP_RAYMIRR)
1185                                 har->hasize = 100.0*texture_value_blend(mtex->def_var,har->hasize/100.0,tin,mtex->raymirrfac,mtex->blendtype);
1186                         /* now what on earth is this good for?? */
1187                         //if(mtex->texco & 16) {
1188                         //      har->alfa= tin;
1189                         //}
1190                 }
1191
1192         return har;
1193 }
1194
1195 /* -------------------------- operations on entire database ----------------------- */
1196
1197 /* ugly function for halos in panorama */
1198 static int panotestclip(Render *re, int do_pano, float *v)
1199 {
1200         /* to be used for halos en infos */
1201         float abs4;
1202         short c=0;
1203
1204         if(do_pano==0) return testclip(v);
1205
1206         abs4= fabs(v[3]);
1207
1208         if(v[2]< -abs4) c=16;           /* this used to be " if(v[2]<0) ", see clippz() */
1209         else if(v[2]> abs4) c+= 32;
1210
1211         if( v[1]>abs4) c+=4;
1212         else if( v[1]< -abs4) c+=8;
1213
1214         abs4*= re->xparts;
1215         if( v[0]>abs4) c+=2;
1216         else if( v[0]< -abs4) c+=1;
1217
1218         return c;
1219 }
1220
1221 /*
1222   This adds the hcs coordinates to vertices. It iterates over all
1223   vertices, halos and faces. After the conversion, we clip in hcs.
1224
1225   Elsewhere, all primites are converted to vertices. 
1226   Called in 
1227   - envmapping (envmap.c)
1228   - shadow buffering (shadbuf.c)
1229 */
1230
1231 void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *),  int do_pano, float xoffs, int do_buckets)
1232 {
1233         ObjectRen *obr;
1234         HaloRen *har = NULL;
1235         float zn, vec[3], hoco[4];
1236         int a;
1237
1238         if(do_pano) {
1239                 float panophi= xoffs;
1240                 
1241                 re->panosi= sin(panophi);
1242                 re->panoco= cos(panophi);
1243         }
1244
1245         for(obr=re->objecttable.first; obr; obr=obr->next) {
1246                 /* calculate view coordinates (and zbuffer value) */
1247                 for(a=0; a<obr->tothalo; a++) {
1248                         if((a & 255)==0) har= obr->bloha[a>>8];
1249                         else har++;
1250
1251                         if(do_pano) {
1252                                 vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
1253                                 vec[1]= har->co[1];
1254                                 vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
1255                         }
1256                         else {
1257                                 VECCOPY(vec, har->co);
1258                         }
1259
1260                         projectfunc(vec, re->winmat, hoco);
1261                         
1262                         /* we clip halos less critical, but not for the Z */
1263                         hoco[0]*= 0.5;
1264                         hoco[1]*= 0.5;
1265                         
1266                         if( panotestclip(re, do_pano, hoco) ) {
1267                                 har->miny= har->maxy= -10000;   /* that way render clips it */
1268                         }
1269                         else if(hoco[3]<0.0) {
1270                                 har->miny= har->maxy= -10000;   /* render clips it */
1271                         }
1272                         else /* do the projection...*/
1273                         {
1274                                 /* bring back hocos */
1275                                 hoco[0]*= 2.0;
1276                                 hoco[1]*= 2.0;
1277                                 
1278                                 zn= hoco[3];
1279                                 har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
1280                                 har->ys= 0.5*re->winy*(1.0+hoco[1]/zn);
1281                         
1282                                 /* this should be the zbuffer coordinate */
1283                                 har->zs= 0x7FFFFF*(hoco[2]/zn);
1284                                 /* taking this from the face clip functions? seems ok... */
1285                                 har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
1286                                 
1287                                 vec[0]+= har->hasize;
1288                                 projectfunc(vec, re->winmat, hoco);
1289                                 vec[0]-= har->hasize;
1290                                 zn= hoco[3];
1291                                 har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn));
1292                         
1293                                 /* this clip is not really OK, to prevent stars to become too large */
1294                                 if(har->type & HA_ONLYSKY) {
1295                                         if(har->rad>3.0) har->rad= 3.0;
1296                                 }
1297                         
1298                                 har->radsq= har->rad*har->rad;
1299                         
1300                                 har->miny= har->ys - har->rad/re->ycor;
1301                                 har->maxy= har->ys + har->rad/re->ycor;
1302                         
1303                                 /* the Zd value is still not really correct for pano */
1304                         
1305                                 vec[2]-= har->hasize;   /* z negative, otherwise it's clipped */
1306                                 projectfunc(vec, re->winmat, hoco);
1307                                 zn= hoco[3];
1308                                 zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn));
1309                                 har->zd= CLAMPIS(zn, 0, INT_MAX);
1310                         
1311                         }
1312                         
1313                 }
1314         }
1315 }
1316
1317 /* ------------------------------------------------------------------------- */
1318
1319 ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[][4], int lay)
1320 {
1321         ObjectInstanceRen *obi;
1322         float mat3[3][3];
1323
1324         obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen");
1325         obi->obr= obr;
1326         obi->ob= ob;
1327         obi->par= par;
1328         obi->index= index;
1329         obi->psysindex= psysindex;
1330         obi->lay= lay;
1331
1332         if(mat) {
1333                 copy_m4_m4(obi->mat, mat);
1334                 copy_m3_m4(mat3, mat);
1335                 invert_m3_m3(obi->nmat, mat3);
1336                 transpose_m3(obi->nmat);
1337                 obi->flag |= R_DUPLI_TRANSFORMED;
1338         }
1339
1340         BLI_addtail(&re->instancetable, obi);
1341
1342         return obi;
1343 }
1344
1345 void RE_makeRenderInstances(Render *re)
1346 {
1347         ObjectInstanceRen *obi, *oldobi;
1348         ListBase newlist;
1349         int tot;
1350
1351         /* convert list of object instances to an array for index based lookup */
1352         tot= BLI_countlist(&re->instancetable);
1353         re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance");
1354         re->totinstance= tot;
1355         newlist.first= newlist.last= NULL;
1356
1357         obi= re->objectinstance;
1358         for(oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
1359                 *obi= *oldobi;
1360
1361                 if(obi->obr) {
1362                         obi->prev= obi->next= NULL;
1363                         BLI_addtail(&newlist, obi);
1364                         obi++;
1365                 }
1366                 else
1367                         re->totinstance--;
1368         }
1369
1370         BLI_freelistN(&re->instancetable);
1371         re->instancetable= newlist;
1372 }
1373
1374 int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4])
1375 {
1376         float mat[4][4], vec[4];
1377         int a, fl, flag= -1;
1378
1379         copy_m4_m4(mat, winmat);
1380
1381         for(a=0; a<8; a++) {
1382                 vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0];
1383                 vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1];
1384                 vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2];
1385                 vec[3]= 1.0;
1386                 mul_m4_v4(mat, vec);
1387
1388                 fl= 0;
1389                 if(bounds) {
1390                         if(vec[0] > bounds[1]*vec[3]) fl |= 1;
1391                         if(vec[0]< bounds[0]*vec[3]) fl |= 2;
1392                         if(vec[1] > bounds[3]*vec[3]) fl |= 4;
1393                         if(vec[1]< bounds[2]*vec[3]) fl |= 8;
1394                 }
1395                 else {
1396                         if(vec[0] < -vec[3]) fl |= 1;
1397                         if(vec[0] > vec[3]) fl |= 2;
1398                         if(vec[1] < -vec[3]) fl |= 4;
1399                         if(vec[1] > vec[3]) fl |= 8;
1400                 }
1401                 if(vec[2] < -vec[3]) fl |= 16;
1402                 if(vec[2] > vec[3]) fl |= 32;
1403
1404                 flag &= fl;
1405                 if(flag==0) return 0;
1406         }
1407
1408         return flag;
1409 }
1410