"Particle" texture coordinates for halo materials:
[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, float *pa_co)
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(mtex->texco & TEXCO_PARTICLE) {
1151                                 /* particle coordinates in range [0,1] */
1152                                 texvec[0] = 2.f * pa_co[0] - 1.f;
1153                                 texvec[1] = 2.f * pa_co[1] - 1.f;
1154                                 texvec[2] = pa_co[2];
1155                         }
1156                         else if(orco) {
1157                                 VECCOPY(texvec, orco);
1158                         }
1159
1160                         hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0);
1161
1162                         //yn= tin*mtex->colfac;
1163                         //zn= tin*mtex->alphafac;
1164                         if(mtex->mapto & MAP_COL) {
1165                                 tex[0]=tr;
1166                                 tex[1]=tg;
1167                                 tex[2]=tb;
1168                                 out[0]=har->r;
1169                                 out[1]=har->g;
1170                                 out[2]=har->b;
1171
1172                                 texture_rgb_blend(in,tex,out,tin,mtex->colfac,mtex->blendtype);
1173                         //      zn= 1.0-yn;
1174                                 //har->r= (yn*tr+ zn*ma->r);
1175                                 //har->g= (yn*tg+ zn*ma->g);
1176                                 //har->b= (yn*tb+ zn*ma->b);
1177                                 har->r= in[0];
1178                                 har->g= in[1];
1179                                 har->b= in[2];
1180                         }
1181
1182                         /* alpha returned, so let's use it instead of intensity */
1183                         if(hasrgb)
1184                                 tin = ta;
1185
1186                         if(mtex->mapto & MAP_ALPHA)
1187                                 har->alfa = texture_value_blend(mtex->def_var,har->alfa,tin,mtex->alphafac,mtex->blendtype);
1188                         if(mtex->mapto & MAP_HAR)
1189                                 har->hard = 1.0+126.0*texture_value_blend(mtex->def_var,((float)har->hard)/127.0,tin,mtex->hardfac,mtex->blendtype);
1190                         if(mtex->mapto & MAP_RAYMIRR)
1191                                 har->hasize = 100.0*texture_value_blend(mtex->def_var,har->hasize/100.0,tin,mtex->raymirrfac,mtex->blendtype);
1192                         /* now what on earth is this good for?? */
1193                         //if(mtex->texco & 16) {
1194                         //      har->alfa= tin;
1195                         //}
1196                 }
1197
1198         return har;
1199 }
1200
1201 /* -------------------------- operations on entire database ----------------------- */
1202
1203 /* ugly function for halos in panorama */
1204 static int panotestclip(Render *re, int do_pano, float *v)
1205 {
1206         /* to be used for halos en infos */
1207         float abs4;
1208         short c=0;
1209
1210         if(do_pano==0) return testclip(v);
1211
1212         abs4= fabs(v[3]);
1213
1214         if(v[2]< -abs4) c=16;           /* this used to be " if(v[2]<0) ", see clippz() */
1215         else if(v[2]> abs4) c+= 32;
1216
1217         if( v[1]>abs4) c+=4;
1218         else if( v[1]< -abs4) c+=8;
1219
1220         abs4*= re->xparts;
1221         if( v[0]>abs4) c+=2;
1222         else if( v[0]< -abs4) c+=1;
1223
1224         return c;
1225 }
1226
1227 /*
1228   This adds the hcs coordinates to vertices. It iterates over all
1229   vertices, halos and faces. After the conversion, we clip in hcs.
1230
1231   Elsewhere, all primites are converted to vertices. 
1232   Called in 
1233   - envmapping (envmap.c)
1234   - shadow buffering (shadbuf.c)
1235 */
1236
1237 void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *),  int do_pano, float xoffs, int do_buckets)
1238 {
1239         ObjectRen *obr;
1240         HaloRen *har = NULL;
1241         float zn, vec[3], hoco[4];
1242         int a;
1243
1244         if(do_pano) {
1245                 float panophi= xoffs;
1246                 
1247                 re->panosi= sin(panophi);
1248                 re->panoco= cos(panophi);
1249         }
1250
1251         for(obr=re->objecttable.first; obr; obr=obr->next) {
1252                 /* calculate view coordinates (and zbuffer value) */
1253                 for(a=0; a<obr->tothalo; a++) {
1254                         if((a & 255)==0) har= obr->bloha[a>>8];
1255                         else har++;
1256
1257                         if(do_pano) {
1258                                 vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
1259                                 vec[1]= har->co[1];
1260                                 vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
1261                         }
1262                         else {
1263                                 VECCOPY(vec, har->co);
1264                         }
1265
1266                         projectfunc(vec, re->winmat, hoco);
1267                         
1268                         /* we clip halos less critical, but not for the Z */
1269                         hoco[0]*= 0.5;
1270                         hoco[1]*= 0.5;
1271                         
1272                         if( panotestclip(re, do_pano, hoco) ) {
1273                                 har->miny= har->maxy= -10000;   /* that way render clips it */
1274                         }
1275                         else if(hoco[3]<0.0) {
1276                                 har->miny= har->maxy= -10000;   /* render clips it */
1277                         }
1278                         else /* do the projection...*/
1279                         {
1280                                 /* bring back hocos */
1281                                 hoco[0]*= 2.0;
1282                                 hoco[1]*= 2.0;
1283                                 
1284                                 zn= hoco[3];
1285                                 har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
1286                                 har->ys= 0.5*re->winy*(1.0+hoco[1]/zn);
1287                         
1288                                 /* this should be the zbuffer coordinate */
1289                                 har->zs= 0x7FFFFF*(hoco[2]/zn);
1290                                 /* taking this from the face clip functions? seems ok... */
1291                                 har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
1292                                 
1293                                 vec[0]+= har->hasize;
1294                                 projectfunc(vec, re->winmat, hoco);
1295                                 vec[0]-= har->hasize;
1296                                 zn= hoco[3];
1297                                 har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn));
1298                         
1299                                 /* this clip is not really OK, to prevent stars to become too large */
1300                                 if(har->type & HA_ONLYSKY) {
1301                                         if(har->rad>3.0) har->rad= 3.0;
1302                                 }
1303                         
1304                                 har->radsq= har->rad*har->rad;
1305                         
1306                                 har->miny= har->ys - har->rad/re->ycor;
1307                                 har->maxy= har->ys + har->rad/re->ycor;
1308                         
1309                                 /* the Zd value is still not really correct for pano */
1310                         
1311                                 vec[2]-= har->hasize;   /* z negative, otherwise it's clipped */
1312                                 projectfunc(vec, re->winmat, hoco);
1313                                 zn= hoco[3];
1314                                 zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn));
1315                                 har->zd= CLAMPIS(zn, 0, INT_MAX);
1316                         
1317                         }
1318                         
1319                 }
1320         }
1321 }
1322
1323 /* ------------------------------------------------------------------------- */
1324
1325 ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[][4], int lay)
1326 {
1327         ObjectInstanceRen *obi;
1328         float mat3[3][3];
1329
1330         obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen");
1331         obi->obr= obr;
1332         obi->ob= ob;
1333         obi->par= par;
1334         obi->index= index;
1335         obi->psysindex= psysindex;
1336         obi->lay= lay;
1337
1338         if(mat) {
1339                 copy_m4_m4(obi->mat, mat);
1340                 copy_m3_m4(mat3, mat);
1341                 invert_m3_m3(obi->nmat, mat3);
1342                 transpose_m3(obi->nmat);
1343                 obi->flag |= R_DUPLI_TRANSFORMED;
1344         }
1345
1346         BLI_addtail(&re->instancetable, obi);
1347
1348         return obi;
1349 }
1350
1351 void RE_makeRenderInstances(Render *re)
1352 {
1353         ObjectInstanceRen *obi, *oldobi;
1354         ListBase newlist;
1355         int tot;
1356
1357         /* convert list of object instances to an array for index based lookup */
1358         tot= BLI_countlist(&re->instancetable);
1359         re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance");
1360         re->totinstance= tot;
1361         newlist.first= newlist.last= NULL;
1362
1363         obi= re->objectinstance;
1364         for(oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
1365                 *obi= *oldobi;
1366
1367                 if(obi->obr) {
1368                         obi->prev= obi->next= NULL;
1369                         BLI_addtail(&newlist, obi);
1370                         obi++;
1371                 }
1372                 else
1373                         re->totinstance--;
1374         }
1375
1376         BLI_freelistN(&re->instancetable);
1377         re->instancetable= newlist;
1378 }
1379
1380 int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4])
1381 {
1382         float mat[4][4], vec[4];
1383         int a, fl, flag= -1;
1384
1385         copy_m4_m4(mat, winmat);
1386
1387         for(a=0; a<8; a++) {
1388                 vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0];
1389                 vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1];
1390                 vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2];
1391                 vec[3]= 1.0;
1392                 mul_m4_v4(mat, vec);
1393
1394                 fl= 0;
1395                 if(bounds) {
1396                         if(vec[0] > bounds[1]*vec[3]) fl |= 1;
1397                         if(vec[0]< bounds[0]*vec[3]) fl |= 2;
1398                         if(vec[1] > bounds[3]*vec[3]) fl |= 4;
1399                         if(vec[1]< bounds[2]*vec[3]) fl |= 8;
1400                 }
1401                 else {
1402                         if(vec[0] < -vec[3]) fl |= 1;
1403                         if(vec[0] > vec[3]) fl |= 2;
1404                         if(vec[1] < -vec[3]) fl |= 4;
1405                         if(vec[1] > vec[3]) fl |= 8;
1406                 }
1407                 if(vec[2] < -vec[3]) fl |= 16;
1408                 if(vec[2] > vec[3]) fl |= 32;
1409
1410                 flag &= fl;
1411                 if(flag==0) return 0;
1412         }
1413
1414         return flag;
1415 }
1416