Merge from Harmonic Skeleton branch
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_arithb.h"
64 #include "BLI_blenlib.h"
65 #include "BLI_memarena.h"
66
67 #include "DNA_material_types.h" 
68 #include "DNA_mesh_types.h" 
69 #include "DNA_meshdata_types.h" 
70 #include "DNA_texture_types.h" 
71
72 #include "BKE_customdata.h"
73 #include "BKE_texture.h" 
74 #include "BKE_DerivedMesh.h"
75
76 #include "RE_render_ext.h"      /* externtex */
77
78 #include "renderpipeline.h"
79 #include "render_types.h"
80 #include "renderdatabase.h"
81 #include "texture.h"
82 #include "strand.h"
83 #include "zbuf.h"
84
85 /* ------------------------------------------------------------------------- */
86
87 /* More dynamic allocation of options for render vertices and faces, so we dont
88    have to reserve this space inside vertices.
89    Important; vertices and faces, should have been created already (to get tables
90    checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
91    the index */
92
93 /* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
94
95 #define RE_STICKY_ELEMS         2
96 #define RE_STRESS_ELEMS         1
97 #define RE_RAD_ELEMS            4
98 #define RE_STRAND_ELEMS         1
99 #define RE_TANGENT_ELEMS        3
100 #define RE_STRESS_ELEMS         1
101 #define RE_WINSPEED_ELEMS       4
102 #define RE_MTFACE_ELEMS         1
103 #define RE_MCOL_ELEMS           4
104 #define RE_UV_ELEMS                     2
105 #define RE_SURFNOR_ELEMS        3
106
107 float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify)
108 {
109         float *sticky;
110         int nr= ver->index>>8;
111         
112         sticky= re->vertnodes[nr].sticky;
113         if(sticky==NULL) {
114                 if(verify) 
115                         sticky= re->vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table");
116                 else
117                         return NULL;
118         }
119         return sticky + (ver->index & 255)*RE_STICKY_ELEMS;
120 }
121
122 float *RE_vertren_get_stress(Render *re, VertRen *ver, int verify)
123 {
124         float *stress;
125         int nr= ver->index>>8;
126         
127         stress= re->vertnodes[nr].stress;
128         if(stress==NULL) {
129                 if(verify) 
130                         stress= re->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
131                 else
132                         return NULL;
133         }
134         return stress + (ver->index & 255)*RE_STRESS_ELEMS;
135 }
136
137 /* this one callocs! */
138 float *RE_vertren_get_rad(Render *re, VertRen *ver, int verify)
139 {
140         float *rad;
141         int nr= ver->index>>8;
142         
143         rad= re->vertnodes[nr].rad;
144         if(rad==NULL) {
145                 if(verify) 
146                         rad= re->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
147                 else
148                         return NULL;
149         }
150         return rad + (ver->index & 255)*RE_RAD_ELEMS;
151 }
152
153 float *RE_vertren_get_strand(Render *re, VertRen *ver, int verify)
154 {
155         float *strand;
156         int nr= ver->index>>8;
157         
158         strand= re->vertnodes[nr].strand;
159         if(strand==NULL) {
160                 if(verify) 
161                         strand= re->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
162                 else
163                         return NULL;
164         }
165         return strand + (ver->index & 255)*RE_STRAND_ELEMS;
166 }
167
168 /* needs calloc */
169 float *RE_vertren_get_tangent(Render *re, VertRen *ver, int verify)
170 {
171         float *tangent;
172         int nr= ver->index>>8;
173         
174         tangent= re->vertnodes[nr].tangent;
175         if(tangent==NULL) {
176                 if(verify) 
177                         tangent= re->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
178                 else
179                         return NULL;
180         }
181         return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
182 }
183
184 /* needs calloc! not all renderverts have them */
185 float *RE_vertren_get_winspeed(Render *re, VertRen *ver, int verify)
186 {
187         float *winspeed;
188         int nr= ver->index>>8;
189         
190         winspeed= re->vertnodes[nr].winspeed;
191         if(winspeed==NULL) {
192                 if(verify) 
193                         winspeed= re->vertnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
194                 else
195                         return NULL;
196         }
197         return winspeed + (ver->index & 255)*RE_WINSPEED_ELEMS;
198 }
199
200 VertRen *RE_vertren_copy(Render *re, VertRen *ver)
201 {
202         VertRen *v1= RE_findOrAddVert(re, re->totvert++);
203         float *fp1, *fp2;
204         int index= v1->index;
205         
206         *v1= *ver;
207         v1->index= index;
208         
209         fp1= RE_vertren_get_sticky(re, ver, 0);
210         if(fp1) {
211                 fp2= RE_vertren_get_sticky(re, v1, 1);
212                 memcpy(fp2, fp1, RE_STICKY_ELEMS*sizeof(float));
213         }
214         fp1= RE_vertren_get_stress(re, ver, 0);
215         if(fp1) {
216                 fp2= RE_vertren_get_stress(re, v1, 1);
217                 memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
218         }
219         fp1= RE_vertren_get_rad(re, ver, 0);
220         if(fp1) {
221                 fp2= RE_vertren_get_rad(re, v1, 1);
222                 memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
223         }
224         fp1= RE_vertren_get_strand(re, ver, 0);
225         if(fp1) {
226                 fp2= RE_vertren_get_strand(re, v1, 1);
227                 memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
228         }
229         fp1= RE_vertren_get_tangent(re, ver, 0);
230         if(fp1) {
231                 fp2= RE_vertren_get_tangent(re, v1, 1);
232                 memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
233         }
234         fp1= RE_vertren_get_winspeed(re, ver, 0);
235         if(fp1) {
236                 fp2= RE_vertren_get_winspeed(re, v1, 1);
237                 memcpy(fp2, fp1, RE_WINSPEED_ELEMS*sizeof(float));
238         }
239         return v1;
240 }
241
242 VertRen *RE_findOrAddVert(Render *re, int nr)
243 {
244         VertTableNode *temp;
245         VertRen *v;
246         int a;
247
248         if(nr<0) {
249                 printf("error in findOrAddVert: %d\n",nr);
250                 return NULL;
251         }
252         a= nr>>8;
253         
254         if (a>=re->vertnodeslen-1) {  /* Need to allocate more columns..., and keep last element NULL for free loop */
255                 temp= re->vertnodes;
256                 
257                 re->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(re->vertnodeslen+TABLEINITSIZE) , "vertnodes");
258                 if(temp) memcpy(re->vertnodes, temp, re->vertnodeslen*sizeof(VertTableNode));
259                 memset(re->vertnodes+re->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
260                 
261                 re->vertnodeslen+=TABLEINITSIZE; 
262                 if(temp) MEM_freeN(temp);       
263         }
264         
265         v= re->vertnodes[a].vert;
266         if(v==NULL) {
267                 int i;
268                 
269                 v= (VertRen *)MEM_callocN(256*sizeof(VertRen),"findOrAddVert");
270                 re->vertnodes[a].vert= v;
271                 
272                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
273                         v[a].index= i;
274                 }
275         }
276         v+= (nr & 255);
277         return v;
278 }
279
280 /* ------------------------------------------------------------------------ */
281
282 MTFace *RE_vlakren_get_tface(Render *re, VlakRen *vlr, int n, char **name, int verify)
283 {
284         VlakTableNode *node;
285         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
286         int index= (n<<8) + vlakindex;
287
288         node= &re->vlaknodes[nr];
289
290         if(verify) {
291                 if(n>=node->totmtface) {
292                         MTFace **mtface= node->mtface;
293                         int size= size= (n+1)*256;
294
295                         node->mtface= MEM_callocN(size*sizeof(MTFace*), "Vlak mtface");
296
297                         if(mtface) {
298                                 size= node->totmtface*256;
299                                 memcpy(node->mtface, mtface, size*sizeof(MTFace*));
300                                 MEM_freeN(mtface);
301                         }
302
303                         node->totmtface= n+1;
304
305                         if (!node->names) {
306                                 size= sizeof(*node->names)*256;
307                                 node->names= MEM_callocN(size, "Vlak names");
308                         }
309                 }
310
311                 if(node->mtface[index]==NULL) {
312                         node->mtface[index]= BLI_memarena_alloc(re->memArena,
313                                 sizeof(MTFace)*RE_MTFACE_ELEMS);
314
315                         node->names[vlakindex]= re->customdata_names.last;
316                 }
317         }
318         else {
319                 if(n>=node->totmtface || node->mtface[index]==NULL)
320                         return NULL;
321
322                 if(name) *name= node->names[vlakindex]->mtface[n];
323         }
324
325         return node->mtface[index];
326 }
327
328 MCol *RE_vlakren_get_mcol(Render *re, VlakRen *vlr, int n, char **name, int verify)
329 {
330         VlakTableNode *node;
331         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
332         int index= (n<<8) + vlakindex;
333
334         node= &re->vlaknodes[nr];
335
336         if(verify) {
337                 if(n>=node->totmcol) {
338                         MCol **mcol= node->mcol;
339                         int size= (n+1)*256;
340
341                         node->mcol= MEM_callocN(size*sizeof(MCol*), "Vlak mcol");
342
343                         if(mcol) {
344                                 size= node->totmcol*256;
345                                 memcpy(node->mcol, mcol, size*sizeof(MCol*));
346                                 MEM_freeN(mcol);
347                         }
348
349                         node->totmcol= n+1;
350
351                         if (!node->names) {
352                                 size= sizeof(*node->names)*256;
353                                 node->names= MEM_callocN(size, "Vlak names");
354                         }
355                 }
356
357                 if(node->mcol[index]==NULL) {
358                         node->mcol[index]= BLI_memarena_alloc(re->memArena,
359                                 sizeof(MCol)*RE_MCOL_ELEMS);
360
361                         node->names[vlakindex]= re->customdata_names.last;
362                 }
363         }
364         else {
365                 if(n>=node->totmcol || node->mcol[index]==NULL)
366                         return NULL;
367
368                 if(name) *name= node->names[vlakindex]->mcol[n];
369         }
370
371         return node->mcol[index];
372 }
373
374 float *RE_vlakren_get_surfnor(Render *re, VlakRen *vlak, int verify)
375 {
376         float *surfnor;
377         int nr= vlak->index>>8;
378         
379         surfnor= re->vlaknodes[nr].surfnor;
380         if(surfnor==NULL) {
381                 if(verify) 
382                         surfnor= re->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
383                 else
384                         return NULL;
385         }
386         return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
387 }
388
389 VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
390 {
391         VlakRen *vlr1 = RE_findOrAddVlak(re, re->totvlak++);
392         MTFace *mtface, *mtface1;
393         MCol *mcol, *mcol1;
394         VlakTableNode *node = &re->vlaknodes[vlr->index>>8];
395         VlakTableNode *node1 = &re->vlaknodes[vlr1->index>>8];
396         float *surfnor, *surfnor1;
397         int i, index = vlr1->index;
398         char *name;
399
400         *vlr1= *vlr;
401         vlr1->index= index;
402
403         for (i=0; (mtface=RE_vlakren_get_tface(re, vlr, i, &name, 0)) != NULL; i++) {
404                 mtface1= RE_vlakren_get_tface(re, vlr1, i, &name, 1);
405                 memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
406         }
407
408         for (i=0; (mcol=RE_vlakren_get_mcol(re, vlr, i, &name, 0)) != NULL; i++) {
409                 mcol1= RE_vlakren_get_mcol(re, vlr1, i, &name, 1);
410                 memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
411         }
412
413         surfnor= RE_vlakren_get_surfnor(re, vlr, 0);
414         if(surfnor) {
415                 surfnor1= RE_vlakren_get_surfnor(re, vlr1, 1);
416                 VECCOPY(surfnor1, surfnor);
417         }
418
419         if (node->names && node1->names)
420                 node1->names[vlr1->index&255] = node->names[vlr->index&255];
421
422         return vlr1;
423 }
424
425 static int vlakren_remap_layer_num(int n, int active)
426 {
427         /* make the active layer the first */
428         if (n == active) return 0;
429         else if (n < active) return n+1;
430         else return n;
431 }
432
433 void RE_vlakren_set_customdata_names(Render *re, CustomData *data)
434 {
435         /* CustomData layer names are stored per object here, because the
436            DerivedMesh which stores the layers is freed */
437         
438         CustomDataNames *cdn= MEM_callocN(sizeof(*cdn), "CustomDataNames");
439         CustomDataLayer *layer;
440         int numlayers, i, mtfn, mcn, n;
441
442         BLI_addtail(&re->customdata_names, cdn);
443
444         if (CustomData_has_layer(data, CD_MTFACE)) {
445                 numlayers= CustomData_number_of_layers(data, CD_MTFACE);
446                 cdn->mtface= MEM_callocN(sizeof(*cdn->mtface)*numlayers, "mtfacenames");
447         }
448
449         if (CustomData_has_layer(data, CD_MCOL)) {
450                 numlayers= CustomData_number_of_layers(data, CD_MCOL);
451                 cdn->mcol= MEM_callocN(sizeof(*cdn->mcol)*numlayers, "mcolnames");
452         }
453
454         for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
455                 layer= &data->layers[i];
456
457                 if (layer->type == CD_MTFACE) {
458                         n= vlakren_remap_layer_num(mtfn++, layer->active_rnd);
459                         strcpy(cdn->mtface[n], layer->name);
460                 }
461                 else if (layer->type == CD_MCOL) {
462                         n= vlakren_remap_layer_num(mcn++, layer->active_rnd);
463                         strcpy(cdn->mcol[n], layer->name);
464                 }
465         }
466 }
467
468 VlakRen *RE_findOrAddVlak(Render *re, int nr)
469 {
470         VlakTableNode *temp;
471         VlakRen *v;
472         int a;
473
474         if(nr<0) {
475                 printf("error in findOrAddVlak: %d\n",nr);
476                 return re->vlaknodes[0].vlak;
477         }
478         a= nr>>8;
479         
480         if (a>=re->vlaknodeslen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
481                 temp= re->vlaknodes;
482                 
483                 re->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(re->vlaknodeslen+TABLEINITSIZE) , "vlaknodes");
484                 if(temp) memcpy(re->vlaknodes, temp, re->vlaknodeslen*sizeof(VlakTableNode));
485                 memset(re->vlaknodes+re->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
486
487                 re->vlaknodeslen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
488                 if(temp) MEM_freeN(temp);       
489         }
490
491         v= re->vlaknodes[a].vlak;
492         
493         if(v==NULL) {
494                 int i;
495
496                 v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen),"findOrAddVlak");
497                 re->vlaknodes[a].vlak= v;
498
499                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
500                         v[a].index= i;
501         }
502         v+= (nr & 255);
503         return v;
504 }
505
506 /* ------------------------------------------------------------------------ */
507
508 float *RE_strandren_get_winspeed(Render *re, StrandRen *strand, int verify)
509 {
510         float *winspeed;
511         int nr= strand->index>>8;
512         
513         winspeed= re->strandnodes[nr].winspeed;
514         if(winspeed==NULL) {
515                 if(verify) 
516                         winspeed= re->strandnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
517                 else
518                         return NULL;
519         }
520         return winspeed + (strand->index & 255)*RE_WINSPEED_ELEMS;
521 }
522
523 float *RE_strandren_get_surfnor(Render *re, StrandRen *strand, int verify)
524 {
525         float *surfnor;
526         int nr= strand->index>>8;
527         
528         surfnor= re->strandnodes[nr].surfnor;
529         if(surfnor==NULL) {
530                 if(verify) 
531                         surfnor= re->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
532                 else
533                         return NULL;
534         }
535         return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
536 }
537
538 float *RE_strandren_get_uv(Render *re, StrandRen *strand, int n, char **name, int verify)
539 {
540         StrandTableNode *node;
541         int nr= strand->index>>8, strandindex= (strand->index&255);
542         int index= (n<<8) + strandindex;
543
544         node= &re->strandnodes[nr];
545
546         if(verify) {
547                 if(n>=node->totuv) {
548                         float **uv= node->uv;
549                         int size= (n+1)*256;
550
551                         node->uv= MEM_callocN(size*sizeof(float*), "Strand uv");
552
553                         if(uv) {
554                                 size= node->totuv*256;
555                                 memcpy(node->uv, uv, size*sizeof(float*));
556                                 MEM_freeN(uv);
557                         }
558
559                         node->totuv= n+1;
560
561                         if (!node->names) {
562                                 size= sizeof(*node->names)*256;
563                                 node->names= MEM_callocN(size, "Strand names");
564                         }
565                 }
566
567                 if(node->uv[index]==NULL) {
568                         node->uv[index]= BLI_memarena_alloc(re->memArena,
569                                 sizeof(float)*RE_UV_ELEMS);
570
571                         node->names[strandindex]= re->customdata_names.last;
572                 }
573         }
574         else {
575                 if(n>=node->totuv || node->uv[index]==NULL)
576                         return NULL;
577
578                 if(name) *name= node->names[strandindex]->mtface[n];
579         }
580
581         return node->uv[index];
582 }
583
584 MCol *RE_strandren_get_mcol(Render *re, StrandRen *strand, int n, char **name, int verify)
585 {
586         StrandTableNode *node;
587         int nr= strand->index>>8, strandindex= (strand->index&255);
588         int index= (n<<8) + strandindex;
589
590         node= &re->strandnodes[nr];
591
592         if(verify) {
593                 if(n>=node->totmcol) {
594                         MCol **mcol= node->mcol;
595                         int size= (n+1)*256;
596
597                         node->mcol= MEM_callocN(size*sizeof(MCol*), "Strand mcol");
598
599                         if(mcol) {
600                                 size= node->totmcol*256;
601                                 memcpy(node->mcol, mcol, size*sizeof(MCol*));
602                                 MEM_freeN(mcol);
603                         }
604
605                         node->totmcol= n+1;
606
607                         if (!node->names) {
608                                 size= sizeof(*node->names)*256;
609                                 node->names= MEM_callocN(size, "Strand names");
610                         }
611                 }
612
613                 if(node->mcol[index]==NULL) {
614                         node->mcol[index]= BLI_memarena_alloc(re->memArena,
615                                 sizeof(MCol)*RE_MCOL_ELEMS);
616
617                         node->names[strandindex]= re->customdata_names.last;
618                 }
619         }
620         else {
621                 if(n>=node->totmcol || node->mcol[index]==NULL)
622                         return NULL;
623
624                 if(name) *name= node->names[strandindex]->mcol[n];
625         }
626
627         return node->mcol[index];
628 }
629
630 StrandRen *RE_findOrAddStrand(Render *re, int nr)
631 {
632         StrandTableNode *temp;
633         StrandRen *v;
634         int a;
635
636         if(nr<0) {
637                 printf("error in findOrAddStrand: %d\n",nr);
638                 return re->strandnodes[0].strand;
639         }
640         a= nr>>8;
641         
642         if (a>=re->strandnodeslen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
643                 temp= re->strandnodes;
644                 
645                 re->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(re->strandnodeslen+TABLEINITSIZE) , "strandnodes");
646                 if(temp) memcpy(re->strandnodes, temp, re->strandnodeslen*sizeof(StrandTableNode));
647                 memset(re->strandnodes+re->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
648
649                 re->strandnodeslen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
650                 if(temp) MEM_freeN(temp);       
651         }
652
653         v= re->strandnodes[a].strand;
654         
655         if(v==NULL) {
656                 int i;
657
658                 v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen),"findOrAddStrand");
659                 re->strandnodes[a].strand= v;
660
661                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
662                         v[a].index= i;
663         }
664         v+= (nr & 255);
665         return v;
666 }
667
668 StrandBuffer *RE_addStrandBuffer(Render *re, Object *ob, int totvert)
669 {
670         StrandBuffer *strandbuf;
671
672         strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
673         strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
674         strandbuf->totvert= totvert;
675         strandbuf->ob= ob;
676
677         BLI_addtail(&re->strandbufs, strandbuf);
678
679         return strandbuf;
680 }
681
682 /* ------------------------------------------------------------------------ */
683
684 void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa, int sst, int est)
685 {
686         ObjectRen *obr= MEM_mallocN(sizeof(ObjectRen), "object render struct");
687         
688         BLI_addtail(&re->objecttable, obr);
689         obr->ob= ob;
690         obr->par= par;
691         obr->index= index;
692         obr->startvert= sve;
693         obr->endvert= eve;
694         obr->startface= sfa;
695         obr->endface= efa;
696         obr->startstrand= sst;
697         obr->endstrand= est;
698 }
699
700 void free_renderdata_vertnodes(VertTableNode *vertnodes)
701 {
702         int a;
703         
704         if(vertnodes==NULL) return;
705         
706         for(a=0; vertnodes[a].vert; a++) {
707                 MEM_freeN(vertnodes[a].vert);
708                 
709                 if(vertnodes[a].rad)
710                         MEM_freeN(vertnodes[a].rad);
711                 if(vertnodes[a].sticky)
712                         MEM_freeN(vertnodes[a].sticky);
713                 if(vertnodes[a].strand)
714                         MEM_freeN(vertnodes[a].strand);
715                 if(vertnodes[a].tangent)
716                         MEM_freeN(vertnodes[a].tangent);
717                 if(vertnodes[a].stress)
718                         MEM_freeN(vertnodes[a].stress);
719                 if(vertnodes[a].winspeed)
720                         MEM_freeN(vertnodes[a].winspeed);
721         }
722         
723         MEM_freeN(vertnodes);
724 }
725
726 void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
727 {
728         int a;
729         
730         if(vlaknodes==NULL) return;
731         
732         for(a=0; vlaknodes[a].vlak; a++) {
733                 MEM_freeN(vlaknodes[a].vlak);
734                 
735                 if(vlaknodes[a].mtface)
736                         MEM_freeN(vlaknodes[a].mtface);
737                 if(vlaknodes[a].mcol)
738                         MEM_freeN(vlaknodes[a].mcol);
739                 if(vlaknodes[a].surfnor)
740                         MEM_freeN(vlaknodes[a].surfnor);
741                 if(vlaknodes[a].names)
742                         MEM_freeN(vlaknodes[a].names);
743         }
744         
745         MEM_freeN(vlaknodes);
746 }
747
748 void free_renderdata_strandnodes(StrandTableNode *strandnodes)
749 {
750         int a;
751         
752         if(strandnodes==NULL) return;
753         
754         for(a=0; strandnodes[a].strand; a++) {
755                 MEM_freeN(strandnodes[a].strand);
756                 
757                 if(strandnodes[a].uv)
758                         MEM_freeN(strandnodes[a].uv);
759                 if(strandnodes[a].mcol)
760                         MEM_freeN(strandnodes[a].mcol);
761                 if(strandnodes[a].winspeed)
762                         MEM_freeN(strandnodes[a].winspeed);
763                 if(strandnodes[a].surfnor)
764                         MEM_freeN(strandnodes[a].surfnor);
765                 if(strandnodes[a].names)
766                         MEM_freeN(strandnodes[a].names);
767         }
768         
769         MEM_freeN(strandnodes);
770 }
771
772 void free_renderdata_tables(Render *re)
773 {
774         StrandBuffer *strandbuf;
775         CustomDataNames *cdn;
776         int a=0;
777         
778         if(re->bloha) {
779                 for(a=0; re->bloha[a]; a++)
780                         MEM_freeN(re->bloha[a]);
781
782                 MEM_freeN(re->bloha);
783                 re->bloha= NULL;
784                 re->blohalen= 0;
785         }
786
787         if(re->vertnodes) {
788                 free_renderdata_vertnodes(re->vertnodes);
789                 re->vertnodes= NULL;
790                 re->vertnodeslen= 0;
791         }
792
793         if(re->vlaknodes) {
794                 free_renderdata_vlaknodes(re->vlaknodes);
795                 re->vlaknodes= NULL;
796                 re->vlaknodeslen= 0;
797         }
798
799         if(re->strandnodes) {
800                 free_renderdata_strandnodes(re->strandnodes);
801                 re->strandnodes= NULL;
802                 re->strandnodeslen= 0;
803         }
804
805         if(re->strandbuckets) {
806                 free_buckets(re->strandbuckets);
807                 re->strandbuckets= NULL;
808         }
809
810         for(cdn=re->customdata_names.first; cdn; cdn=cdn->next) {
811                 if(cdn->mtface)
812                         MEM_freeN(cdn->mtface);
813                 if(cdn->mcol)
814                         MEM_freeN(cdn->mcol);
815         }
816
817         for(strandbuf=re->strandbufs.first; strandbuf; strandbuf=strandbuf->next)
818                 if(strandbuf->vert) MEM_freeN(strandbuf->vert);
819         BLI_freelistN(&re->strandbufs);
820
821         BLI_freelistN(&re->customdata_names);
822         BLI_freelistN(&re->objecttable);
823 }
824
825
826 /* ------------------------------------------------------------------------ */
827
828 HaloRen *RE_findOrAddHalo(Render *re, int nr)
829 {
830         HaloRen *h, **temp;
831         int a;
832
833         if(nr<0) {
834                 printf("error in findOrAddHalo: %d\n",nr);
835                 return NULL;
836         }
837         a= nr>>8;
838         
839         if (a>=re->blohalen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
840                 //printf("Allocating %i more halo groups.  %i total.\n", 
841                 //      TABLEINITSIZE, re->blohalen+TABLEINITSIZE );
842                 temp=re->bloha;
843                 
844                 re->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(re->blohalen+TABLEINITSIZE) , "Bloha");
845                 if(temp) memcpy(re->bloha, temp, re->blohalen*sizeof(void*));
846                 memset(&(re->bloha[re->blohalen]), 0, TABLEINITSIZE*sizeof(void*));
847                 re->blohalen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
848                 if(temp) MEM_freeN(temp);       
849         }
850         
851         h= re->bloha[a];
852         if(h==NULL) {
853                 h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen),"findOrAdHalo");
854                 re->bloha[a]= h;
855         }
856         h+= (nr & 255);
857         return h;
858 }
859
860 /* ------------------------------------------------------------------------- */
861
862 HaloRen *RE_inithalo(Render *re, Material *ma,   float *vec,   float *vec1, 
863                                   float *orco,   float hasize,   float vectsize, int seed)
864 {
865         HaloRen *har;
866         MTex *mtex;
867         float tin, tr, tg, tb, ta;
868         float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
869
870         if(hasize==0.0) return NULL;
871
872         projectverto(vec, re->winmat, hoco);
873         if(hoco[3]==0.0) return NULL;
874         if(vec1) {
875                 projectverto(vec1, re->winmat, hoco1);
876                 if(hoco1[3]==0.0) return NULL;
877         }
878
879         har= RE_findOrAddHalo(re, re->tothalo++);
880         VECCOPY(har->co, vec);
881         har->hasize= hasize;
882
883         /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
884         /* we do it here for sorting of halos */
885         zn= hoco[3];
886         har->xs= 0.5*re->winx*(hoco[0]/zn);
887         har->ys= 0.5*re->winy*(hoco[1]/zn);
888         har->zs= 0x7FFFFF*(hoco[2]/zn);
889         
890         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); 
891         
892         /* halovect */
893         if(vec1) {
894
895                 har->type |= HA_VECT;
896
897                 xn=  har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
898                 yn=  har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
899                 if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
900                 else zn= atan2(yn, xn);
901
902                 har->sin= sin(zn);
903                 har->cos= cos(zn);
904                 zn= VecLenf(vec1, vec);
905
906                 har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
907                 
908                 VecSubf(har->no, vec, vec1);
909                 Normalize(har->no);
910         }
911
912         if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
913
914         har->alfa= ma->alpha;
915         har->r= ma->r;
916         har->g= ma->g;
917         har->b= ma->b;
918         har->add= (255.0*ma->add);
919         har->mat= ma;
920         har->hard= ma->har;
921         har->seed= seed % 256;
922
923         if(ma->mode & MA_STAR) har->starpoints= ma->starc;
924         if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
925         if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
926         if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
927
928
929         if(ma->mtex[0]) {
930
931                 if( (ma->mode & MA_HALOTEX) ) har->tex= 1;
932                 else {
933
934                         mtex= ma->mtex[0];
935                         VECCOPY(texvec, vec);
936
937                         if(mtex->texco & TEXCO_NORM) {
938                                 ;
939                         }
940                         else if(mtex->texco & TEXCO_OBJECT) {
941                                 /* texvec[0]+= imatbase->ivec[0]; */
942                                 /* texvec[1]+= imatbase->ivec[1]; */
943                                 /* texvec[2]+= imatbase->ivec[2]; */
944                                 /* Mat3MulVecfl(imatbase->imat, texvec); */
945                         }
946                         else {
947                                 if(orco) {
948                                         VECCOPY(texvec, orco);
949                                 }
950                         }
951
952                         externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta);
953
954                         yn= tin*mtex->colfac;
955                         zn= tin*mtex->varfac;
956
957                         if(mtex->mapto & MAP_COL) {
958                                 zn= 1.0-yn;
959                                 har->r= (yn*tr+ zn*ma->r);
960                                 har->g= (yn*tg+ zn*ma->g);
961                                 har->b= (yn*tb+ zn*ma->b);
962                         }
963                         if(mtex->texco & 16) {
964                                 har->alfa= tin;
965                         }
966                 }
967         }
968
969         return har;
970 }
971
972 HaloRen *RE_inithalo_particle(Render *re, DerivedMesh *dm, Material *ma,   float *vec,   float *vec1, 
973                                   float *orco, float *uvco, float hasize, float vectsize, int seed)
974 {
975         HaloRen *har;
976         MTex *mtex;
977         float tin, tr, tg, tb, ta;
978         float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3],tex[3],out[3];
979         int i;
980
981         if(hasize==0.0) return NULL;
982
983         projectverto(vec, re->winmat, hoco);
984         if(hoco[3]==0.0) return NULL;
985         if(vec1) {
986                 projectverto(vec1, re->winmat, hoco1);
987                 if(hoco1[3]==0.0) return NULL;
988         }
989
990         har= RE_findOrAddHalo(re, re->tothalo++);
991         VECCOPY(har->co, vec);
992         har->hasize= hasize;
993
994         /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
995         /* we do it here for sorting of halos */
996         zn= hoco[3];
997         har->xs= 0.5*re->winx*(hoco[0]/zn);
998         har->ys= 0.5*re->winy*(hoco[1]/zn);
999         har->zs= 0x7FFFFF*(hoco[2]/zn);
1000         
1001         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); 
1002         
1003         /* halovect */
1004         if(vec1) {
1005
1006                 har->type |= HA_VECT;
1007
1008                 xn=  har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
1009                 yn=  har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
1010                 if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
1011                 else zn= atan2(yn, xn);
1012
1013                 har->sin= sin(zn);
1014                 har->cos= cos(zn);
1015                 zn= VecLenf(vec1, vec)*0.5;
1016
1017                 har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
1018                 
1019                 VecSubf(har->no, vec, vec1);
1020                 Normalize(har->no);
1021         }
1022
1023         if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
1024
1025         har->alfa= ma->alpha;
1026         har->r= ma->r;
1027         har->g= ma->g;
1028         har->b= ma->b;
1029         har->add= (255.0*ma->add);
1030         har->mat= ma;
1031         har->hard= ma->har;
1032         har->seed= seed % 256;
1033
1034         if(ma->mode & MA_STAR) har->starpoints= ma->starc;
1035         if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
1036         if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
1037         if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
1038
1039         if((ma->mode & MA_HALOTEX) && ma->mtex[0]){
1040                 har->tex= 1;
1041                 i=1;
1042         }
1043         
1044         for(i=0; i<MAX_MTEX; i++)
1045                 if(ma->mtex[i] && (ma->septex & (1<<i))==0) {
1046                         mtex= ma->mtex[i];
1047                         VECCOPY(texvec, vec);
1048
1049                         if(mtex->texco & TEXCO_NORM) {
1050                                 ;
1051                         }
1052                         else if(mtex->texco & TEXCO_OBJECT) {
1053                                 if(mtex->object){
1054                                         float imat[4][4];
1055                                         /* imat should really be cached somewhere before this */
1056                                         Mat4Invert(imat,mtex->object->obmat);
1057                                         Mat4MulVecfl(imat,texvec);
1058                                 }
1059                                 /* texvec[0]+= imatbase->ivec[0]; */
1060                                 /* texvec[1]+= imatbase->ivec[1]; */
1061                                 /* texvec[2]+= imatbase->ivec[2]; */
1062                                 /* Mat3MulVecfl(imatbase->imat, texvec); */
1063                         }
1064                         else if(mtex->texco & TEXCO_GLOB){
1065                                 VECCOPY(texvec,vec);
1066                         }
1067                         else if(mtex->texco & TEXCO_UV && uvco){
1068                                 int uv_index=CustomData_get_named_layer_index(&dm->faceData,CD_MTFACE,mtex->uvname);
1069                                 if(uv_index<0)
1070                                         uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE);
1071
1072                                 uv_index-=CustomData_get_layer_index(&dm->faceData,CD_MTFACE);
1073
1074                                 texvec[0]=2.0f*uvco[2*uv_index]-1.0f;
1075                                 texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f;
1076                                 texvec[2]=0.0f;
1077                         }
1078                         else if(orco) {
1079                                 VECCOPY(texvec, orco);
1080                         }
1081
1082                         externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta);
1083
1084                         //yn= tin*mtex->colfac;
1085                         //zn= tin*mtex->varfac;
1086                         if(mtex->mapto & MAP_COL) {
1087                                 tex[0]=tr;
1088                                 tex[1]=tg;
1089                                 tex[2]=tb;
1090                                 out[0]=har->r;
1091                                 out[1]=har->g;
1092                                 out[2]=har->b;
1093
1094                                 texture_rgb_blend(in,tex,out,tin,mtex->colfac,mtex->blendtype);
1095                         //      zn= 1.0-yn;
1096                                 //har->r= (yn*tr+ zn*ma->r);
1097                                 //har->g= (yn*tg+ zn*ma->g);
1098                                 //har->b= (yn*tb+ zn*ma->b);
1099                                 har->r= in[0];
1100                                 har->g= in[1];
1101                                 har->b= in[2];
1102                         }
1103                         if(mtex->mapto & MAP_ALPHA)
1104                                 har->alfa = texture_value_blend(mtex->def_var,har->alfa,tin,mtex->varfac,mtex->blendtype,mtex->maptoneg & MAP_ALPHA);
1105                         if(mtex->mapto & MAP_HAR)
1106                                 har->hard = 1.0+126.0*texture_value_blend(mtex->def_var,((float)har->hard)/127.0,tin,mtex->varfac,mtex->blendtype,mtex->maptoneg & MAP_HAR);
1107                         if(mtex->mapto & MAP_RAYMIRR)
1108                                 har->hasize = 100.0*texture_value_blend(mtex->def_var,har->hasize/100.0,tin,mtex->varfac,mtex->blendtype,mtex->maptoneg & MAP_RAYMIRR);
1109                         /* now what on earth is this good for?? */
1110                         //if(mtex->texco & 16) {
1111                         //      har->alfa= tin;
1112                         //}
1113                 }
1114
1115         return har;
1116 }
1117
1118 /* -------------------------- operations on entire database ----------------------- */
1119
1120 /* ugly function for halos in panorama */
1121 static int panotestclip(Render *re, int do_pano, float *v)
1122 {
1123         /* to be used for halos en infos */
1124         float abs4;
1125         short c=0;
1126
1127         if(do_pano==0) return testclip(v);
1128
1129         abs4= fabs(v[3]);
1130
1131         if(v[2]< -abs4) c=16;           /* this used to be " if(v[2]<0) ", see clippz() */
1132         else if(v[2]> abs4) c+= 32;
1133
1134         if( v[1]>abs4) c+=4;
1135         else if( v[1]< -abs4) c+=8;
1136
1137         abs4*= re->xparts;
1138         if( v[0]>abs4) c+=2;
1139         else if( v[0]< -abs4) c+=1;
1140
1141         return c;
1142 }
1143
1144 /*
1145   This adds the hcs coordinates to vertices. It iterates over all
1146   vertices, halos and faces. After the conversion, we clip in hcs.
1147
1148   Elsewhere, all primites are converted to vertices. 
1149   Called in 
1150   - envmapping (envmap.c)
1151   - shadow buffering (shadbuf.c)
1152 */
1153
1154 void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *),  int do_pano, float xoffs, int do_buckets)
1155 {
1156         VlakRen *vlr = NULL;
1157         VertRen *ver = NULL;
1158         HaloRen *har = NULL;
1159         float zn, vec[3], hoco[4];
1160         int a;
1161
1162         if(do_pano) {
1163                 float panophi= xoffs;
1164                 
1165                 re->panosi= sin(panophi);
1166                 re->panoco= cos(panophi);
1167         }
1168         
1169    /* calculate view coordinates (and zbuffer value) */
1170         for(a=0; a< re->totvert;a++) {
1171                 if((a & 255)==0) ver= RE_findOrAddVert(re, a);
1172                 else ver++;
1173
1174                 if(do_pano) {
1175                         vec[0]= re->panoco*ver->co[0] + re->panosi*ver->co[2];
1176                         vec[1]= ver->co[1];
1177                         vec[2]= -re->panosi*ver->co[0] + re->panoco*ver->co[2];
1178                 }
1179                 else {
1180                         VECCOPY(vec, ver->co);
1181                 }
1182                 /* Go from wcs to hcs ... */
1183                 projectfunc(vec, re->winmat, ver->ho);
1184                 /* ... and clip in that system. */
1185                 ver->clip = testclip(ver->ho);
1186                 /* 
1187                    Because all other ops are performed in other systems, this is 
1188                    the only thing that has to be done.
1189                 */
1190         }
1191
1192    /* calculate view coordinates (and zbuffer value) */
1193         for(a=0; a<re->tothalo; a++) {
1194                 if((a & 255)==0) har= re->bloha[a>>8];
1195                 else har++;
1196
1197                 if(do_pano) {
1198                         vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
1199                         vec[1]= har->co[1];
1200                         vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
1201                 }
1202                 else {
1203                         VECCOPY(vec, har->co);
1204                 }
1205
1206                 projectfunc(vec, re->winmat, hoco);
1207                 
1208                 /* we clip halos less critical, but not for the Z */
1209                 hoco[0]*= 0.5;
1210                 hoco[1]*= 0.5;
1211                 
1212                 if( panotestclip(re, do_pano, hoco) ) {
1213                         har->miny= har->maxy= -10000;   /* that way render clips it */
1214                 }
1215                 else if(hoco[3]<0.0) {
1216                         har->miny= har->maxy= -10000;   /* render clips it */
1217                 }
1218                 else /* do the projection...*/
1219                 {
1220                         /* bring back hocos */
1221                         hoco[0]*= 2.0;
1222                         hoco[1]*= 2.0;
1223                         
1224                         zn= hoco[3];
1225                         har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
1226                         har->ys= 0.5*re->winy*(1.0+hoco[1]/zn);
1227                 
1228                         /* this should be the zbuffer coordinate */
1229                         har->zs= 0x7FFFFF*(hoco[2]/zn);
1230                         /* taking this from the face clip functions? seems ok... */
1231                         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
1232                         
1233                         vec[0]+= har->hasize;
1234                         projectfunc(vec, re->winmat, hoco);
1235                         vec[0]-= har->hasize;
1236                         zn= hoco[3];
1237                         har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn));
1238                 
1239                         /* this clip is not really OK, to prevent stars to become too large */
1240                         if(har->type & HA_ONLYSKY) {
1241                                 if(har->rad>3.0) har->rad= 3.0;
1242                         }
1243                 
1244                         har->radsq= har->rad*har->rad;
1245                 
1246                         har->miny= har->ys - har->rad/re->ycor;
1247                         har->maxy= har->ys + har->rad/re->ycor;
1248                 
1249                         /* the Zd value is still not really correct for pano */
1250                 
1251                         vec[2]-= har->hasize;   /* z negative, otherwise it's clipped */
1252                         projectfunc(vec, re->winmat, hoco);
1253                         zn= hoco[3];
1254                         zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn));
1255                         har->zd= CLAMPIS(zn, 0, INT_MAX);
1256                 
1257                 }
1258                 
1259         }
1260
1261         /* set flags at 0 if clipped away */
1262         for(a=0; a<re->totvlak; a++) {
1263                 if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
1264                 else vlr++;
1265
1266                 if(!re->excludeob || vlr->ob != re->excludeob) {
1267                         vlr->flag |= R_VISIBLE;
1268                         if(vlr->v4) {
1269                                 if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip & vlr->v4->clip) vlr->flag &= ~R_VISIBLE;
1270                         }
1271                         else if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip) vlr->flag &= ~R_VISIBLE;
1272                 }
1273                 else
1274                         vlr->flag &= ~R_VISIBLE;
1275         }
1276
1277         project_strands(re, projectfunc, do_pano, do_buckets);
1278 }
1279
1280 /* ------------------------------------------------------------------------- */
1281
1282 void set_normalflags(Render *re)
1283 {
1284         VlakRen *vlr = NULL;
1285         float *v1, xn, yn, zn;
1286         int a1, doflip;
1287         
1288         /* switch normal 'snproj' values (define which axis is the optimal one for calculations) */
1289         for(a1=0; a1<re->totvlak; a1++) {
1290                 if((a1 & 255)==0) vlr= re->vlaknodes[a1>>8].vlak;
1291                 else vlr++;
1292                 
1293                 vlr->noflag= 0;
1294
1295                 /* abuse of this flag... this is code that just sets face normal in direction of camera */
1296                 /* that convention we should get rid of */
1297                 if((vlr->flag & R_NOPUNOFLIP)==0) {
1298                         
1299                         doflip= 0;
1300                         if(re->r.mode & R_ORTHO) {
1301                                 if(vlr->n[2]>0.0) doflip= 1;
1302                         }
1303                         else {
1304                                 v1= vlr->v1->co;
1305                                 if( (v1[0]*vlr->n[0] +v1[1]*vlr->n[1] +v1[2]*vlr->n[2])<0.0 ) doflip= 1;
1306                         }
1307                         if(doflip) {
1308                                 vlr->n[0]= -vlr->n[0];
1309                                 vlr->n[1]= -vlr->n[1];
1310                                 vlr->n[2]= -vlr->n[2];
1311                                 vlr->noflag |= R_FLIPPED_NO;
1312                         }
1313                 }
1314                 
1315                 /* recalculate puno. Displace & flipped matrices can screw up */
1316                 vlr->puno= 0;
1317                 if(!(vlr->flag & R_TANGENT)) {
1318                         if( Inpf(vlr->n, vlr->v1->n) < 0.0 ) vlr->puno |= ME_FLIPV1;
1319                         if( Inpf(vlr->n, vlr->v2->n) < 0.0 ) vlr->puno |= ME_FLIPV2;
1320                         if( Inpf(vlr->n, vlr->v3->n) < 0.0 ) vlr->puno |= ME_FLIPV3;
1321                         if(vlr->v4 && Inpf(vlr->n, vlr->v4->n) < 0.0 ) vlr->puno |= ME_FLIPV4;
1322                 }                               
1323                 xn= fabs(vlr->n[0]);
1324                 yn= fabs(vlr->n[1]);
1325                 zn= fabs(vlr->n[2]);
1326                 if(zn>=xn && zn>=yn) vlr->noflag |= R_SNPROJ_X;
1327                 else if(yn>=xn && yn>=zn) vlr->noflag |= R_SNPROJ_Y;
1328                 else vlr->noflag |= R_SNPROJ_Z;
1329
1330         }
1331 }
1332
1333
1334