57f0f689871b0414aec56a61f31f7324d35026c2
[blender.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
75 #include "RE_render_ext.h"      /* externtex */
76
77 #include "renderpipeline.h"
78 #include "render_types.h"
79 #include "renderdatabase.h"
80 #include "texture.h"
81 #include "zbuf.h"
82
83 /* ------------------------------------------------------------------------- */
84
85 /* More dynamic allocation of options for render vertices and faces, so we dont
86    have to reserve this space inside vertices.
87    Important; vertices and faces, should have been created already (to get tables
88    checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
89    the index */
90
91 /* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
92
93 #define RE_STICKY_ELEMS         2
94 #define RE_STRESS_ELEMS         1
95 #define RE_RAD_ELEMS            4
96 #define RE_STRAND_ELEMS         1
97 #define RE_TANGENT_ELEMS        3
98 #define RE_STRESS_ELEMS         1
99 #define RE_WINSPEED_ELEMS       4
100 #define RE_MTFACE_ELEMS         1
101 #define RE_MCOL_ELEMS           4
102
103 float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify)
104 {
105         float *sticky;
106         int nr= ver->index>>8;
107         
108         sticky= re->vertnodes[nr].sticky;
109         if(sticky==NULL) {
110                 if(verify) 
111                         sticky= re->vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table");
112                 else
113                         return NULL;
114         }
115         return sticky + (ver->index & 255)*RE_STICKY_ELEMS;
116 }
117
118 float *RE_vertren_get_stress(Render *re, VertRen *ver, int verify)
119 {
120         float *stress;
121         int nr= ver->index>>8;
122         
123         stress= re->vertnodes[nr].stress;
124         if(stress==NULL) {
125                 if(verify) 
126                         stress= re->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
127                 else
128                         return NULL;
129         }
130         return stress + (ver->index & 255)*RE_STRESS_ELEMS;
131 }
132
133 /* this one callocs! */
134 float *RE_vertren_get_rad(Render *re, VertRen *ver, int verify)
135 {
136         float *rad;
137         int nr= ver->index>>8;
138         
139         rad= re->vertnodes[nr].rad;
140         if(rad==NULL) {
141                 if(verify) 
142                         rad= re->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
143                 else
144                         return NULL;
145         }
146         return rad + (ver->index & 255)*RE_RAD_ELEMS;
147 }
148
149 float *RE_vertren_get_strand(Render *re, VertRen *ver, int verify)
150 {
151         float *strand;
152         int nr= ver->index>>8;
153         
154         strand= re->vertnodes[nr].strand;
155         if(strand==NULL) {
156                 if(verify) 
157                         strand= re->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
158                 else
159                         return NULL;
160         }
161         return strand + (ver->index & 255)*RE_STRAND_ELEMS;
162 }
163
164 /* needs calloc */
165 float *RE_vertren_get_tangent(Render *re, VertRen *ver, int verify)
166 {
167         float *tangent;
168         int nr= ver->index>>8;
169         
170         tangent= re->vertnodes[nr].tangent;
171         if(tangent==NULL) {
172                 if(verify) 
173                         tangent= re->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
174                 else
175                         return NULL;
176         }
177         return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
178 }
179
180 /* needs calloc! not all renderverts have them */
181 float *RE_vertren_get_winspeed(Render *re, VertRen *ver, int verify)
182 {
183         float *winspeed;
184         int nr= ver->index>>8;
185         
186         winspeed= re->vertnodes[nr].winspeed;
187         if(winspeed==NULL) {
188                 if(verify) 
189                         winspeed= re->vertnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
190                 else
191                         return NULL;
192         }
193         return winspeed + (ver->index & 255)*RE_WINSPEED_ELEMS;
194 }
195
196 VertRen *RE_vertren_copy(Render *re, VertRen *ver)
197 {
198         VertRen *v1= RE_findOrAddVert(re, re->totvert++);
199         float *fp1, *fp2;
200         int index= v1->index;
201         
202         *v1= *ver;
203         v1->index= index;
204         
205         fp1= RE_vertren_get_sticky(re, ver, 0);
206         if(fp1) {
207                 fp2= RE_vertren_get_sticky(re, v1, 1);
208                 memcpy(fp2, fp1, RE_STICKY_ELEMS*sizeof(float));
209         }
210         fp1= RE_vertren_get_stress(re, ver, 0);
211         if(fp1) {
212                 fp2= RE_vertren_get_stress(re, v1, 1);
213                 memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
214         }
215         fp1= RE_vertren_get_rad(re, ver, 0);
216         if(fp1) {
217                 fp2= RE_vertren_get_rad(re, v1, 1);
218                 memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
219         }
220         fp1= RE_vertren_get_strand(re, ver, 0);
221         if(fp1) {
222                 fp2= RE_vertren_get_strand(re, v1, 1);
223                 memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
224         }
225         fp1= RE_vertren_get_tangent(re, ver, 0);
226         if(fp1) {
227                 fp2= RE_vertren_get_tangent(re, v1, 1);
228                 memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
229         }
230         fp1= RE_vertren_get_winspeed(re, ver, 0);
231         if(fp1) {
232                 fp2= RE_vertren_get_winspeed(re, v1, 1);
233                 memcpy(fp2, fp1, RE_WINSPEED_ELEMS*sizeof(float));
234         }
235         return v1;
236 }
237
238 VertRen *RE_findOrAddVert(Render *re, int nr)
239 {
240         VertTableNode *temp;
241         VertRen *v;
242         int a;
243
244         if(nr<0) {
245                 printf("error in findOrAddVert: %d\n",nr);
246                 return NULL;
247         }
248         a= nr>>8;
249         
250         if (a>=re->vertnodeslen-1) {  /* Need to allocate more columns..., and keep last element NULL for free loop */
251                 temp= re->vertnodes;
252                 
253                 re->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(re->vertnodeslen+TABLEINITSIZE) , "vertnodes");
254                 if(temp) memcpy(re->vertnodes, temp, re->vertnodeslen*sizeof(VertTableNode));
255                 memset(re->vertnodes+re->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
256                 
257                 re->vertnodeslen+=TABLEINITSIZE; 
258                 if(temp) MEM_freeN(temp);       
259         }
260         
261         v= re->vertnodes[a].vert;
262         if(v==NULL) {
263                 int i;
264                 
265                 v= (VertRen *)MEM_callocN(256*sizeof(VertRen),"findOrAddVert");
266                 re->vertnodes[a].vert= v;
267                 
268                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
269                         v[a].index= i;
270                 }
271         }
272         v+= (nr & 255);
273         return v;
274 }
275
276 /* ------------------------------------------------------------------------ */
277
278 MTFace *RE_vlakren_get_tface(Render *re, VlakRen *vlr, int n, char **name, int verify)
279 {
280         VlakTableNode *node;
281         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
282         int index= (n<<8) + vlakindex;
283
284         node= &re->vlaknodes[nr];
285
286         if(verify) {
287                 if(n>=node->totmtface) {
288                         MTFace **mtface= node->mtface;
289                         int size= size= (n+1)*256;
290
291                         node->mtface= MEM_callocN(size*sizeof(MTFace*), "Vlak mtface");
292
293                         if(mtface) {
294                                 size= node->totmtface*256;
295                                 memcpy(node->mtface, mtface, size*sizeof(MTFace*));
296                                 MEM_freeN(mtface);
297                         }
298
299                         node->totmtface= n+1;
300
301                         if (!node->names) {
302                                 size= sizeof(*node->names)*256;
303                                 node->names= MEM_callocN(size, "Vlak names");
304                         }
305                 }
306
307                 if(node->mtface[index]==NULL) {
308                         node->mtface[index]= BLI_memarena_alloc(re->memArena,
309                                 sizeof(MTFace)*RE_MTFACE_ELEMS);
310
311                         node->names[vlakindex]= re->customdata_names.last;
312                 }
313         }
314         else {
315                 if(n>=node->totmtface || node->mtface[index]==NULL)
316                         return NULL;
317
318                 if(name) *name= node->names[vlakindex]->mtface[n];
319         }
320
321         return node->mtface[index];
322 }
323
324 MCol *RE_vlakren_get_mcol(Render *re, VlakRen *vlr, int n, char **name, int verify)
325 {
326         VlakTableNode *node;
327         int nr= vlr->index>>8, vlakindex= (vlr->index&255);
328         int index= (n<<8) + vlakindex;
329
330         node= &re->vlaknodes[nr];
331
332         if(verify) {
333                 if(n>=node->totmcol) {
334                         MCol **mcol= node->mcol;
335                         int size= (n+1)*256;
336
337                         node->mcol= MEM_callocN(size*sizeof(MCol*), "Vlak mcol");
338
339                         if(mcol) {
340                                 size= node->totmcol*256;
341                                 memcpy(node->mcol, mcol, size*sizeof(MCol*));
342                                 MEM_freeN(mcol);
343                         }
344
345                         node->totmcol= n+1;
346
347                         if (!node->names) {
348                                 size= sizeof(*node->names)*256;
349                                 node->names= MEM_callocN(size, "Vlak names");
350                         }
351                 }
352
353                 if(node->mcol[index]==NULL) {
354                         node->mcol[index]= BLI_memarena_alloc(re->memArena,
355                                 sizeof(MCol)*RE_MCOL_ELEMS);
356
357                         node->names[vlakindex]= re->customdata_names.last;
358                 }
359         }
360         else {
361                 if(n>=node->totmcol || node->mcol[index]==NULL)
362                         return NULL;
363
364                 if(name) *name= node->names[vlakindex]->mcol[n];
365         }
366
367         return node->mcol[index];
368 }
369
370 VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
371 {
372         VlakRen *vlr1 = RE_findOrAddVlak(re, re->totvlak++);
373         MTFace *mtface, *mtface1;
374         MCol *mcol, *mcol1;
375         VlakTableNode *node = &re->vlaknodes[vlr->index>>8];
376         VlakTableNode *node1 = &re->vlaknodes[vlr1->index>>8];
377         int i, index = vlr1->index;
378         char *name;
379
380         *vlr1= *vlr;
381         vlr1->index= index;
382
383         for (i=0; (mtface=RE_vlakren_get_tface(re, vlr, i, &name, 0)) != NULL; i++) {
384                 mtface1= RE_vlakren_get_tface(re, vlr1, i, &name, 1);
385                 memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
386         }
387
388         for (i=0; (mcol=RE_vlakren_get_mcol(re, vlr, i, &name, 0)) != NULL; i++) {
389                 mcol1= RE_vlakren_get_mcol(re, vlr1, i, &name, 1);
390                 memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
391         }
392
393         if (node->names && node1->names)
394                 node1->names[vlr1->index&255] = node->names[vlr->index&255];
395
396         return vlr1;
397 }
398
399 static int vlakren_remap_layer_num(int n, int active)
400 {
401         /* make the active layer the first */
402         if (n == active) return 0;
403         else if (n < active) return n+1;
404         else return n;
405 }
406
407 void RE_vlakren_set_customdata_names(Render *re, CustomData *data)
408 {
409         /* CustomData layer names are stored per object here, because the
410            DerivedMesh which stores the layers is freed */
411         
412         CustomDataNames *cdn= MEM_callocN(sizeof(*cdn), "CustomDataNames");
413         CustomDataLayer *layer;
414         int numlayers, i, mtfn, mcn, n;
415
416         BLI_addtail(&re->customdata_names, cdn);
417
418         if (CustomData_has_layer(data, CD_MTFACE)) {
419                 numlayers= CustomData_number_of_layers(data, CD_MTFACE);
420                 cdn->mtface= MEM_callocN(sizeof(*cdn->mtface)*numlayers, "mtfacenames");
421         }
422
423         if (CustomData_has_layer(data, CD_MCOL)) {
424                 numlayers= CustomData_number_of_layers(data, CD_MCOL);
425                 cdn->mcol= MEM_callocN(sizeof(*cdn->mcol)*numlayers, "mcolnames");
426         }
427
428         for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
429                 layer= &data->layers[i];
430
431                 if (layer->type == CD_MTFACE) {
432                         n= vlakren_remap_layer_num(mtfn++, layer->active_rnd);
433                         strcpy(cdn->mtface[n], layer->name);
434                 }
435                 else if (layer->type == CD_MCOL) {
436                         n= vlakren_remap_layer_num(mcn++, layer->active_rnd);
437                         strcpy(cdn->mcol[n], layer->name);
438                 }
439         }
440 }
441
442 VlakRen *RE_findOrAddVlak(Render *re, int nr)
443 {
444         VlakTableNode *temp;
445         VlakRen *v;
446         int a;
447
448         if(nr<0) {
449                 printf("error in findOrAddVlak: %d\n",nr);
450                 return re->vlaknodes[0].vlak;
451         }
452         a= nr>>8;
453         
454         if (a>=re->vlaknodeslen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
455                 temp= re->vlaknodes;
456                 
457                 re->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(re->vlaknodeslen+TABLEINITSIZE) , "vlaknodes");
458                 if(temp) memcpy(re->vlaknodes, temp, re->vlaknodeslen*sizeof(VlakTableNode));
459                 memset(re->vlaknodes+re->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
460
461                 re->vlaknodeslen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
462                 if(temp) MEM_freeN(temp);       
463         }
464
465         v= re->vlaknodes[a].vlak;
466         
467         if(v==NULL) {
468                 int i;
469
470                 v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen),"findOrAddVlak");
471                 re->vlaknodes[a].vlak= v;
472
473                 for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
474                         v[a].index= i;
475         }
476         v+= (nr & 255);
477         return v;
478 }
479
480 /* ------------------------------------------------------------------------ */
481
482 void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa)
483 {
484         ObjectRen *obr= MEM_mallocN(sizeof(ObjectRen), "object render struct");
485         
486         BLI_addtail(&re->objecttable, obr);
487         obr->ob= ob;
488         obr->par= par;
489         obr->index= index;
490         obr->startvert= sve;
491         obr->endvert= eve;
492         obr->startface= sfa;
493         obr->endface= efa;
494 }
495
496 void free_renderdata_vertnodes(VertTableNode *vertnodes)
497 {
498         int a;
499         
500         if(vertnodes==NULL) return;
501         
502         for(a=0; vertnodes[a].vert; a++) {
503                 MEM_freeN(vertnodes[a].vert);
504                 
505                 if(vertnodes[a].rad)
506                         MEM_freeN(vertnodes[a].rad);
507                 if(vertnodes[a].sticky)
508                         MEM_freeN(vertnodes[a].sticky);
509                 if(vertnodes[a].strand)
510                         MEM_freeN(vertnodes[a].strand);
511                 if(vertnodes[a].tangent)
512                         MEM_freeN(vertnodes[a].tangent);
513                 if(vertnodes[a].stress)
514                         MEM_freeN(vertnodes[a].stress);
515                 if(vertnodes[a].winspeed)
516                         MEM_freeN(vertnodes[a].winspeed);
517         }
518         
519         MEM_freeN(vertnodes);
520 }
521
522 void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
523 {
524         int a;
525         
526         if(vlaknodes==NULL) return;
527         
528         for(a=0; vlaknodes[a].vlak; a++) {
529                 MEM_freeN(vlaknodes[a].vlak);
530                 
531                 if(vlaknodes[a].mtface)
532                         MEM_freeN(vlaknodes[a].mtface);
533                 if(vlaknodes[a].mcol)
534                         MEM_freeN(vlaknodes[a].mcol);
535                 if(vlaknodes[a].names)
536                         MEM_freeN(vlaknodes[a].names);
537         }
538         
539         MEM_freeN(vlaknodes);
540 }
541
542 void free_renderdata_tables(Render *re)
543 {
544         int a=0;
545         CustomDataNames *cdn;
546         
547         if(re->bloha) {
548                 for(a=0; re->bloha[a]; a++)
549                         MEM_freeN(re->bloha[a]);
550
551                 MEM_freeN(re->bloha);
552                 re->bloha= NULL;
553                 re->blohalen= 0;
554         }
555
556         if(re->vertnodes) {
557                 free_renderdata_vertnodes(re->vertnodes);
558                 re->vertnodes= NULL;
559                 re->vertnodeslen= 0;
560         }
561
562         if(re->vlaknodes) {
563                 free_renderdata_vlaknodes(re->vlaknodes);
564                 re->vlaknodes= NULL;
565                 re->vlaknodeslen= 0;
566         }
567
568         for(cdn=re->customdata_names.first; cdn; cdn=cdn->next) {
569                 if(cdn->mtface)
570                         MEM_freeN(cdn->mtface);
571                 if(cdn->mcol)
572                         MEM_freeN(cdn->mcol);
573         }
574
575         BLI_freelistN(&re->customdata_names);
576         BLI_freelistN(&re->objecttable);
577 }
578
579
580 /* ------------------------------------------------------------------------ */
581
582 HaloRen *RE_findOrAddHalo(Render *re, int nr)
583 {
584         HaloRen *h, **temp;
585         int a;
586
587         if(nr<0) {
588                 printf("error in findOrAddHalo: %d\n",nr);
589                 return NULL;
590         }
591         a= nr>>8;
592         
593         if (a>=re->blohalen-1){  /* Need to allocate more columns..., and keep last element NULL for free loop */
594                 //printf("Allocating %i more halo groups.  %i total.\n", 
595                 //      TABLEINITSIZE, re->blohalen+TABLEINITSIZE );
596                 temp=re->bloha;
597                 
598                 re->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(re->blohalen+TABLEINITSIZE) , "Bloha");
599                 if(temp) memcpy(re->bloha, temp, re->blohalen*sizeof(void*));
600                 memset(&(re->bloha[re->blohalen]), 0, TABLEINITSIZE*sizeof(void*));
601                 re->blohalen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
602                 if(temp) MEM_freeN(temp);       
603         }
604         
605         h= re->bloha[a];
606         if(h==NULL) {
607                 h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen),"findOrAdHalo");
608                 re->bloha[a]= h;
609         }
610         h+= (nr & 255);
611         return h;
612 }
613
614 /* ------------------------------------------------------------------------- */
615
616 HaloRen *RE_inithalo(Render *re, Material *ma,   float *vec,   float *vec1, 
617                                   float *orco,   float hasize,   float vectsize, int seed)
618 {
619         HaloRen *har;
620         MTex *mtex;
621         float tin, tr, tg, tb, ta;
622         float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
623
624         if(hasize==0.0) return NULL;
625
626         projectverto(vec, re->winmat, hoco);
627         if(hoco[3]==0.0) return NULL;
628         if(vec1) {
629                 projectverto(vec1, re->winmat, hoco1);
630                 if(hoco1[3]==0.0) return NULL;
631         }
632
633         har= RE_findOrAddHalo(re, re->tothalo++);
634         VECCOPY(har->co, vec);
635         har->hasize= hasize;
636
637         /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
638         /* we do it here for sorting of halos */
639         zn= hoco[3];
640         har->xs= 0.5*re->winx*(hoco[0]/zn);
641         har->ys= 0.5*re->winy*(hoco[1]/zn);
642         har->zs= 0x7FFFFF*(hoco[2]/zn);
643         
644         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); 
645         
646         /* halovect */
647         if(vec1) {
648
649                 har->type |= HA_VECT;
650
651                 xn=  har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
652                 yn=  har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
653                 if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
654                 else zn= atan2(yn, xn);
655
656                 har->sin= sin(zn);
657                 har->cos= cos(zn);
658                 zn= VecLenf(vec1, vec);
659
660                 har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
661                 
662                 VecSubf(har->no, vec, vec1);
663                 Normalize(har->no);
664         }
665
666         if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
667
668         har->alfa= ma->alpha;
669         har->r= ma->r;
670         har->g= ma->g;
671         har->b= ma->b;
672         har->add= (255.0*ma->add);
673         har->mat= ma;
674         har->hard= ma->har;
675         har->seed= seed % 256;
676
677         if(ma->mode & MA_STAR) har->starpoints= ma->starc;
678         if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
679         if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
680         if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
681
682
683         if(ma->mtex[0]) {
684
685                 if( (ma->mode & MA_HALOTEX) ) har->tex= 1;
686                 else {
687
688                         mtex= ma->mtex[0];
689                         VECCOPY(texvec, vec);
690
691                         if(mtex->texco & TEXCO_NORM) {
692                                 ;
693                         }
694                         else if(mtex->texco & TEXCO_OBJECT) {
695                                 /* texvec[0]+= imatbase->ivec[0]; */
696                                 /* texvec[1]+= imatbase->ivec[1]; */
697                                 /* texvec[2]+= imatbase->ivec[2]; */
698                                 /* Mat3MulVecfl(imatbase->imat, texvec); */
699                         }
700                         else {
701                                 if(orco) {
702                                         VECCOPY(texvec, orco);
703                                 }
704                         }
705
706                         externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta);
707
708                         yn= tin*mtex->colfac;
709                         zn= tin*mtex->varfac;
710
711                         if(mtex->mapto & MAP_COL) {
712                                 zn= 1.0-yn;
713                                 har->r= (yn*tr+ zn*ma->r);
714                                 har->g= (yn*tg+ zn*ma->g);
715                                 har->b= (yn*tb+ zn*ma->b);
716                         }
717                         if(mtex->texco & 16) {
718                                 har->alfa= tin;
719                         }
720                 }
721         }
722
723         return har;
724 }
725
726 /* -------------------------- operations on entire database ----------------------- */
727
728 /* ugly function for halos in panorama */
729 static int panotestclip(Render *re, int do_pano, float *v)
730 {
731         /* to be used for halos en infos */
732         float abs4;
733         short c=0;
734
735         if(do_pano==0) return testclip(v);
736
737         abs4= fabs(v[3]);
738
739         if(v[2]< -abs4) c=16;           /* this used to be " if(v[2]<0) ", see clippz() */
740         else if(v[2]> abs4) c+= 32;
741
742         if( v[1]>abs4) c+=4;
743         else if( v[1]< -abs4) c+=8;
744
745         abs4*= re->xparts;
746         if( v[0]>abs4) c+=2;
747         else if( v[0]< -abs4) c+=1;
748
749         return c;
750 }
751
752 /*
753   This adds the hcs coordinates to vertices. It iterates over all
754   vertices, halos and faces. After the conversion, we clip in hcs.
755
756   Elsewhere, all primites are converted to vertices. 
757   Called in 
758   - envmapping (envmap.c)
759   - shadow buffering (shadbuf.c)
760 */
761
762 void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *),  int do_pano, float xoffs)
763 {
764         VlakRen *vlr = NULL;
765         VertRen *ver = NULL;
766         HaloRen *har = NULL;
767         float zn, vec[3], hoco[4];
768         int a;
769         
770         if(do_pano) {
771                 float panophi= xoffs;
772                 
773                 re->panosi= sin(panophi);
774                 re->panoco= cos(panophi);
775         }
776         
777    /* calculate view coordinates (and zbuffer value) */
778         for(a=0; a< re->totvert;a++) {
779                 if((a & 255)==0) ver= RE_findOrAddVert(re, a);
780                 else ver++;
781
782                 if(do_pano) {
783                         vec[0]= re->panoco*ver->co[0] + re->panosi*ver->co[2];
784                         vec[1]= ver->co[1];
785                         vec[2]= -re->panosi*ver->co[0] + re->panoco*ver->co[2];
786                 }
787                 else {
788                         VECCOPY(vec, ver->co);
789                 }
790                 /* Go from wcs to hcs ... */
791                 projectfunc(vec, re->winmat, ver->ho);
792                 /* ... and clip in that system. */
793                 ver->clip = testclip(ver->ho);
794                 /* 
795                    Because all other ops are performed in other systems, this is 
796                    the only thing that has to be done.
797                 */
798         }
799
800    /* calculate view coordinates (and zbuffer value) */
801         for(a=0; a<re->tothalo; a++) {
802                 if((a & 255)==0) har= re->bloha[a>>8];
803                 else har++;
804
805                 if(do_pano) {
806                         vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
807                         vec[1]= har->co[1];
808                         vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
809                 }
810                 else {
811                         VECCOPY(vec, har->co);
812                 }
813
814                 projectfunc(vec, re->winmat, hoco);
815                 
816                 /* we clip halos less critical, but not for the Z */
817                 hoco[0]*= 0.5;
818                 hoco[1]*= 0.5;
819                 
820                 if( panotestclip(re, do_pano, hoco) ) {
821                         har->miny= har->maxy= -10000;   /* that way render clips it */
822                 }
823                 else if(hoco[3]<0.0) {
824                         har->miny= har->maxy= -10000;   /* render clips it */
825                 }
826                 else /* do the projection...*/
827                 {
828                         /* bring back hocos */
829                         hoco[0]*= 2.0;
830                         hoco[1]*= 2.0;
831                         
832                         zn= hoco[3];
833                         har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
834                         har->ys= 0.5*re->winy*(1.0+hoco[1]/zn);
835                 
836                         /* this should be the zbuffer coordinate */
837                         har->zs= 0x7FFFFF*(hoco[2]/zn);
838                         /* taking this from the face clip functions? seems ok... */
839                         har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
840                         
841                         vec[0]+= har->hasize;
842                         projectfunc(vec, re->winmat, hoco);
843                         vec[0]-= har->hasize;
844                         zn= hoco[3];
845                         har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn));
846                 
847                         /* this clip is not really OK, to prevent stars to become too large */
848                         if(har->type & HA_ONLYSKY) {
849                                 if(har->rad>3.0) har->rad= 3.0;
850                         }
851                 
852                         har->radsq= har->rad*har->rad;
853                 
854                         har->miny= har->ys - har->rad/re->ycor;
855                         har->maxy= har->ys + har->rad/re->ycor;
856                 
857                         /* the Zd value is still not really correct for pano */
858                 
859                         vec[2]-= har->hasize;   /* z negative, otherwise it's clipped */
860                         projectfunc(vec, re->winmat, hoco);
861                         zn= hoco[3];
862                         zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn));
863                         har->zd= CLAMPIS(zn, 0, INT_MAX);
864                 
865                 }
866                 
867         }
868
869         /* set flags at 0 if clipped away */
870         for(a=0; a<re->totvlak; a++) {
871                 if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
872                 else vlr++;
873
874                         vlr->flag |= R_VISIBLE;
875                         if(vlr->v4) {
876                                 if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip & vlr->v4->clip) vlr->flag &= ~R_VISIBLE;
877                         }
878                         else if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip) vlr->flag &= ~R_VISIBLE;
879
880                 }
881
882 }
883
884 /* ------------------------------------------------------------------------- */
885
886 void set_normalflags(Render *re)
887 {
888         VlakRen *vlr = NULL;
889         float *v1, xn, yn, zn;
890         int a1, doflip;
891         
892         /* switch normal 'snproj' values (define which axis is the optimal one for calculations) */
893         for(a1=0; a1<re->totvlak; a1++) {
894                 if((a1 & 255)==0) vlr= re->vlaknodes[a1>>8].vlak;
895                 else vlr++;
896                 
897                 /* abuse of this flag... this is code that just sets face normal in direction of camera */
898                 /* that convention we should get rid of */
899                 if((vlr->flag & R_NOPUNOFLIP)==0) {
900                         
901                         doflip= 0;
902                         if(re->r.mode & R_ORTHO) {
903                                 if(vlr->n[2]>0.0) doflip= 1;
904                         }
905                         else {
906                                 v1= vlr->v1->co;
907                                 if( (v1[0]*vlr->n[0] +v1[1]*vlr->n[1] +v1[2]*vlr->n[2])<0.0 ) doflip= 1;
908                         }
909                         if(doflip) {
910                                 vlr->n[0]= -vlr->n[0];
911                                 vlr->n[1]= -vlr->n[1];
912                                 vlr->n[2]= -vlr->n[2];
913                         }
914                 }
915                 
916                 /* recalculate puno. Displace & flipped matrices can screw up */
917                 vlr->puno= 0;
918                 if(!(vlr->flag & R_TANGENT)) {
919                         if( Inpf(vlr->n, vlr->v1->n) < 0.0 ) vlr->puno |= ME_FLIPV1;
920                         if( Inpf(vlr->n, vlr->v2->n) < 0.0 ) vlr->puno |= ME_FLIPV2;
921                         if( Inpf(vlr->n, vlr->v3->n) < 0.0 ) vlr->puno |= ME_FLIPV3;
922                         if(vlr->v4 && Inpf(vlr->n, vlr->v4->n) < 0.0 ) vlr->puno |= ME_FLIPV4;
923                 }                               
924                 xn= fabs(vlr->n[0]);
925                 yn= fabs(vlr->n[1]);
926                 zn= fabs(vlr->n[2]);
927                 if(zn>=xn && zn>=yn) vlr->snproj= 0;
928                 else if(yn>=xn && yn>=zn) vlr->snproj= 1;
929                 else vlr->snproj= 2;
930
931         }
932 }
933
934
935