- added Mesh->derived and Mesh->decimated DerivedMesh pointers
[blender.git] / source / blender / src / drawmesh.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <math.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_arithb.h"
44
45 #include "IMB_imbuf_types.h"
46
47 #include "DNA_image_types.h"
48 #include "DNA_lamp_types.h"
49 #include "DNA_material_types.h"
50 #include "DNA_mesh_types.h"
51 #include "DNA_meshdata_types.h"
52 #include "DNA_object_types.h"
53 #include "DNA_property_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_view3d_types.h"
56
57 #include "BKE_bmfont.h"
58 #include "BKE_displist.h"
59 #include "BKE_DerivedMesh.h"
60 #include "BKE_effect.h"
61 #include "BKE_global.h"
62 #include "BKE_image.h"
63 #include "BKE_main.h"
64 #include "BKE_material.h"
65 #include "BKE_mesh.h"
66 #include "BKE_object.h"
67 #include "BKE_property.h"
68 #include "BKE_utildefines.h"
69
70 #include "BIF_resources.h"
71 #include "BIF_gl.h"
72 #include "BIF_glutil.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_resources.h"
75
76 #include "BDR_editface.h"
77 #include "BDR_vpaint.h"
78 #include "BDR_drawmesh.h"
79
80 #include "BSE_drawview.h"
81
82 #include "blendef.h"
83 #include "nla.h"
84
85 //#include "glext.h"
86 /* some local functions */
87 #if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__) && !defined(__linux__) && !defined(WIN32)
88         #define glBindTexture(A,B)     glBindTextureEXT(A,B)
89         #define glGenTextures(A,B)     glGenTexturesEXT(A,B)
90         #define glDeleteTextures(A,B)  glDeleteTexturesEXT(A,B)
91         #define glPolygonOffset(A,B)  glPolygonOffsetEXT(A,B)
92
93 #else
94
95 /* #define GL_FUNC_ADD_EXT                                      GL_FUNC_ADD */
96 /* #define GL_FUNC_REVERSE_SUBTRACT_EXT GL_FUNC_REVERSE_SUBTRACT */
97 /* #define GL_POLYGON_OFFSET_EXT                        GL_POLYGON_OFFSET */
98
99 #endif
100
101         /* (n&(n-1)) zeros the least significant bit of n */
102 static int is_pow2(int num) {
103         return ((num)&(num-1))==0;
104 }
105 static int smaller_pow2(int num) {
106         while (!is_pow2(num))
107                 num= num&(num-1);
108         return num;     
109 }
110
111 static int fCurtile=0, fCurmode=0,fCurtileXRep=0,fCurtileYRep=0;
112 static Image *fCurpage=0;
113 static short fTexwindx, fTexwindy, fTexwinsx, fTexwinsy;
114 static int fDoMipMap = 1;
115 static int fLinearMipMap = 0;
116
117 /* local prototypes --------------- */
118 void update_realtime_textures(void);
119
120
121 /*  static int source, dest; also not used */
122
123 /**
124  * Enables or disable mipmapping for realtime images.
125  * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
126  */
127 void set_mipmap(int mipmap)
128 {
129         if (fDoMipMap != (mipmap != 0)) {
130                 free_all_realtime_images();
131                 fDoMipMap = mipmap != 0;
132         }
133 }
134
135
136 /**
137  * Returns the current setting for mipmapping.
138  */
139 int get_mipmap(void)
140 {
141         return fDoMipMap;
142 }
143
144 /**
145  * Enables or disable linear mipmap setting for realtime images (textures).
146  * Note that this will will destroy all texture bindings in OpenGL.
147  * @see free_realtime_image()
148  * @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0).
149  */
150 void set_linear_mipmap(int linear)
151 {
152         if (fLinearMipMap != (linear != 0)) {
153                 free_all_realtime_images();
154                 fLinearMipMap = linear != 0;
155         }
156 }
157
158 /**
159  * Returns the current setting for linear mipmapping.
160  */
161 int get_linear_mipmap(void)
162 {
163         return fLinearMipMap;
164 }
165
166
167 /**
168  * Resets the realtime image cache variables.
169  */
170 void clear_realtime_image_cache()
171 {
172         fCurpage = NULL;
173         fCurtile = 0;
174         fCurmode = 0;
175         fCurtileXRep = 0;
176         fCurtileYRep = 0;
177 }
178
179 /* REMEMBER!  Changes here must go into my_set_tpage() as well */
180 int set_tpage(TFace *tface)
181 {       
182         static int alphamode= -1;
183         static TFace *lasttface= 0;
184         Image *ima;
185         unsigned int *rect=NULL, *bind;
186         int tpx=0, tpy=0, tilemode, tileXRep,tileYRep;
187         
188         /* disable */
189         if(tface==0) {
190                 if(lasttface==0) return 0;
191                 
192                 lasttface= 0;
193                 fCurtile= 0;
194                 fCurpage= 0;
195                 if(fCurmode!=0) {
196                         glMatrixMode(GL_TEXTURE);
197                         glLoadIdentity();
198                         glMatrixMode(GL_MODELVIEW);
199                 }
200                 fCurmode= 0;
201                 fCurtileXRep=0;
202                 fCurtileYRep=0;
203                 alphamode= -1;
204                 
205                 glDisable(GL_BLEND);
206                 glDisable(GL_TEXTURE_2D);
207                 glDisable(GL_TEXTURE_GEN_S);
208                 glDisable(GL_TEXTURE_GEN_T);
209
210                 return 0;
211         }
212         lasttface= tface;
213
214         if( alphamode != tface->transp) {
215                 alphamode= tface->transp;
216
217                 if(alphamode) {
218                         glEnable(GL_BLEND);
219                         
220                         if(alphamode==TF_ADD) {
221                                 glBlendFunc(GL_ONE, GL_ONE);
222                         /*      glBlendEquationEXT(GL_FUNC_ADD_EXT); */
223                         }
224                         else if(alphamode==TF_ALPHA) {
225                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
226                         /*      glBlendEquationEXT(GL_FUNC_ADD_EXT); */
227                         }
228                         /* else { */
229                         /*      glBlendFunc(GL_ONE, GL_ONE); */
230                         /*      glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
231                         /* } */
232                 }
233                 else glDisable(GL_BLEND);
234         }
235
236         ima= tface->tpage;
237
238         /* Enable or disable reflection mapping */
239         if (ima && (ima->flag & IMA_REFLECT)){
240
241 //              glActiveTextureARB(GL_TEXTURE0_ARB);
242                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
243                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
244
245                 glEnable(GL_TEXTURE_GEN_S);
246                 glEnable(GL_TEXTURE_GEN_T);
247
248                 /* Handle multitexturing here */
249         }
250         else{
251                 glDisable(GL_TEXTURE_GEN_S);
252                 glDisable(GL_TEXTURE_GEN_T);
253         }
254
255         tilemode= tface->mode & TF_TILES;
256         tileXRep = 0;
257         tileYRep = 0;
258         if (ima)
259         {
260                 tileXRep = ima->xrep;
261                 tileYRep = ima->yrep;
262         }
263
264
265         if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurtileXRep==tileXRep && fCurtileYRep == tileYRep) return ima!=0;
266
267         if(tilemode!=fCurmode || fCurtileXRep!=tileXRep || fCurtileYRep != tileYRep)
268         {
269                 glMatrixMode(GL_TEXTURE);
270                 glLoadIdentity();
271                 
272                 if(tilemode && ima!=0)
273                         glScalef(ima->xrep, ima->yrep, 1.0);
274
275                 glMatrixMode(GL_MODELVIEW);
276         }
277
278         if(ima==0 || ima->ok==0) {
279                 glDisable(GL_TEXTURE_2D);
280                 
281                 fCurtile= tface->tile;
282                 fCurpage= 0;
283                 fCurmode= tilemode;
284                 fCurtileXRep = tileXRep;
285                 fCurtileYRep = tileYRep;
286
287                 return 0;
288         }
289
290         if(ima->ibuf==0) {
291                 load_image(ima, IB_rect, G.sce, G.scene->r.cfra);
292                 
293                 if(ima->ibuf==0) {
294                         ima->ok= 0;
295
296                         fCurtile= tface->tile;
297                         fCurpage= 0;
298                         fCurmode= tilemode;
299                         fCurtileXRep = tileXRep;
300                         fCurtileYRep = tileYRep;
301                         
302                         glDisable(GL_TEXTURE_2D);
303                         return 0;
304                 }
305                 
306         }
307
308         if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
309         else fCurtile= tface->tile;
310
311         if(tilemode) {
312
313                 if(ima->repbind==0) make_repbind(ima);
314                 
315                 if(fCurtile>=ima->totbind) fCurtile= 0;
316                 
317                 /* this happens when you change repeat buttons */
318                 if(ima->repbind) bind= ima->repbind+fCurtile;
319                 else bind= &ima->bindcode;
320                 
321                 if(*bind==0) {
322                         
323                         fTexwindx= ima->ibuf->x/ima->xrep;
324                         fTexwindy= ima->ibuf->y/ima->yrep;
325                         
326                         if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1;
327         
328                         fTexwinsy= fCurtile / ima->xrep;
329                         fTexwinsx= fCurtile - fTexwinsy*ima->xrep;
330         
331                         fTexwinsx*= fTexwindx;
332                         fTexwinsy*= fTexwindy;
333         
334                         tpx= fTexwindx;
335                         tpy= fTexwindy;
336
337                         rect= ima->ibuf->rect + fTexwinsy*ima->ibuf->x + fTexwinsx;
338                 }
339         }
340         else {
341                 bind= &ima->bindcode;
342                 
343                 if(*bind==0) {
344                         tpx= ima->ibuf->x;
345                         tpy= ima->ibuf->y;
346                         rect= ima->ibuf->rect;
347                 }
348         }
349
350         if(*bind==0) {
351                 int rectw= tpx, recth= tpy;
352                 unsigned int *tilerect= NULL, *scalerect= NULL;
353
354                 /*
355                  * Maarten:
356                  * According to Ton this code is not needed anymore. It was used only
357                  * in really old Blenders.
358                  * Reevan:
359                  * Actually it is needed for backwards compatibility.  Simpledemo 6 does not display correctly without it.
360                  */
361 #if 1
362                 if (tilemode) {
363                         int y;
364                                 
365                         tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
366                         for (y=0; y<recth; y++) {
367                                 unsigned int *rectrow= &rect[y*ima->ibuf->x];
368                                 unsigned int *tilerectrow= &tilerect[y*rectw];
369                                         
370                                 memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
371                         }
372                                 
373                         rect= tilerect;
374                 }
375 #endif
376                 if (!is_pow2(rectw) || !is_pow2(recth)) {
377                         rectw= smaller_pow2(rectw);
378                         recth= smaller_pow2(recth);
379                         
380                         scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
381                         gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
382                         rect= scalerect;
383                 }
384
385                 glGenTextures(1, (GLuint *)bind);
386                 
387                 if((G.f & G_DEBUG) || !*bind) {
388                         GLenum error = glGetError();
389                         printf("Texture: %s\n", ima->id.name+2);
390                         printf("name: %d, tpx: %d\n", *bind, tpx);
391                         printf("tile: %d, mode: %d\n", fCurtile, tilemode);
392                         if (error)
393                                 printf("error: %s\n", gluErrorString(error));
394                 }
395                 glBindTexture( GL_TEXTURE_2D, *bind);
396
397                 if (!fDoMipMap)
398                 {
399                         glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
400                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
401                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
402                 } else
403                 {
404                         int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
405                         
406                         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
407                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
408                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
409                 }
410
411                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
412                         
413                 if (tilerect)
414                         MEM_freeN(tilerect);
415                 if (scalerect)
416                         MEM_freeN(scalerect);
417         }
418         else glBindTexture( GL_TEXTURE_2D, *bind);
419         
420         glEnable(GL_TEXTURE_2D);
421
422         fCurpage= ima;
423         fCurmode= tilemode;
424         fCurtileXRep = tileXRep;
425         fCurtileYRep = tileYRep;
426
427         return 1;
428 }
429
430 void free_realtime_image(Image *ima)
431 {
432         if(ima->bindcode) {
433                 glDeleteTextures(1, (GLuint *)&ima->bindcode);
434                 ima->bindcode= 0;
435         }
436         if(ima->repbind) {
437                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
438         
439                 MEM_freeN(ima->repbind);
440                 ima->repbind= 0;
441         }
442 }
443
444 void free_all_realtime_images(void)
445 {
446         Image* ima;
447
448         ima= G.main->image.first;
449         while(ima) {
450                 free_realtime_image(ima);
451                 ima= ima->id.next;
452         }
453 }
454
455 void make_repbind(Image *ima)
456 {
457         if(ima==0 || ima->ibuf==0) return;
458
459         if(ima->repbind) {
460                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
461                 MEM_freeN(ima->repbind);
462                 ima->repbind= 0;
463         }
464         ima->totbind= ima->xrep*ima->yrep;
465         if(ima->totbind>1) {
466                 ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
467         }
468 }
469
470 void update_realtime_textures()
471 {
472         Image *ima;
473         
474         ima= G.main->image.first;
475         while(ima) {
476                 if(ima->tpageflag & IMA_TWINANIM) {
477                         if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
478                 
479                         /* check: is bindcode not in the array? Free. (to do) */
480                         
481                         ima->lastframe++;
482                         if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
483                         
484                 }
485                 ima= ima->id.next;
486         }
487 }
488
489
490 void spack(unsigned int ucol)
491 {
492         char *cp= (char *)&ucol;
493         
494         glColor3ub(cp[3], cp[2], cp[1]);
495 }
496
497 void draw_tfaces3D(Object *ob, Mesh *me)
498 {
499         MFace *mface;
500         TFace *tface;
501         DispList *dl;
502         float *v1, *v2, *v3, *v4;
503         float *av1= NULL, *av2= NULL, *av3= NULL, *av4= NULL, *extverts= NULL; 
504         int a, activeFaceInSelection= 0;
505         
506         if(me==0 || me->tface==0) return;
507
508         dl= find_displist(&ob->disp, DL_VERTS);
509         if (dl) extverts= dl->verts;
510
511         glEnable(GL_DEPTH_TEST);
512         glDisable(GL_LIGHTING);
513         bglPolygonOffset(1.0);
514
515         /* Draw (Hidden) Edges */
516         if(G.f & G_DRAWEDGES || G.f & G_HIDDENEDGES){ 
517                 BIF_ThemeColor(TH_EDGE_FACESEL);
518
519                 mface= me->mface;
520                 tface= me->tface;
521                 for(a=me->totface; a>0; a--, mface++, tface++) {
522                         if(mface->v3==0) continue;
523                         if(tface->flag & TF_HIDE) {
524                                 if(!(G.f & G_HIDDENEDGES)) continue;
525                         }
526                         else if(!(G.f & G_DRAWEDGES)) continue;
527                         
528                         if(extverts) {
529                                 v1= extverts+3*mface->v1;
530                                 v2= extverts+3*mface->v2;
531                                 v3= extverts+3*mface->v3;
532                                 v4= mface->v4?(extverts+3*mface->v4):NULL;
533                         } else {
534                                 v1= (me->mvert+mface->v1)->co;
535                                 v2= (me->mvert+mface->v2)->co;
536                                 v3= (me->mvert+mface->v3)->co;
537                                 v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
538                         }
539
540                         glBegin(GL_LINE_LOOP);
541                                 glVertex3fv(v1);
542                                 glVertex3fv(v2);
543                                 glVertex3fv(v3);
544                                 if(v4) glVertex3fv(v4);
545                         glEnd();
546                 }
547         }
548
549         if(G.f & G_DRAWSEAMS) {
550                 BIF_ThemeColor(TH_EDGE_SEAM);
551                 glLineWidth(2);
552
553                 glBegin(GL_LINES);
554                 mface= me->mface;
555                 tface= me->tface;
556                 for(a=me->totface; a>0; a--, mface++, tface++) {
557                         if(mface->v3==0) continue;
558                         if(tface->flag & TF_HIDE) continue;
559
560                         if(extverts) {
561                                 v1= extverts+3*mface->v1;
562                                 v2= extverts+3*mface->v2;
563                                 v3= extverts+3*mface->v3;
564                                 v4= mface->v4?(extverts+3*mface->v4):NULL;
565                         } else {
566                                 v1= (me->mvert+mface->v1)->co;
567                                 v2= (me->mvert+mface->v2)->co;
568                                 v3= (me->mvert+mface->v3)->co;
569                                 v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
570                         }
571
572                         if(tface->unwrap & TF_SEAM1) {
573                                 glVertex3fv(v1);
574                                 glVertex3fv(v2);
575                         }
576
577                         if(tface->unwrap & TF_SEAM2) {
578                                 glVertex3fv(v2);
579                                 glVertex3fv(v3);
580                         }
581
582                         if(tface->unwrap & TF_SEAM3) {
583                                 glVertex3fv(v3);
584                                 if(v4) glVertex3fv(v4);
585                                 else glVertex3fv(v1);
586                         }
587
588                         if(v4 && tface->unwrap & TF_SEAM4) {
589                                 glVertex3fv(v4);
590                                 glVertex3fv(v1);
591                         }
592                 }
593                 glEnd();
594
595                 glLineWidth(1);
596         }
597
598         /* Draw Selected Faces in transparent purple */
599         if(G.f & G_DRAWFACES) {
600                 glEnable(GL_BLEND);
601                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
602                 BIF_ThemeColor4(TH_FACE_SELECT);
603
604                 mface= me->mface;
605                 tface= me->tface;
606                 for(a=me->totface; a>0; a--, mface++, tface++) {
607                         if(mface->v3==0) continue;
608                         if(tface->flag & TF_HIDE) continue;
609                 
610                         if(tface->flag & TF_SELECT) {
611                                 if(extverts) {
612                                         v1= extverts+3*mface->v1;
613                                         v2= extverts+3*mface->v2;
614                                         v3= extverts+3*mface->v3;
615                                         v4= mface->v4?(extverts+3*mface->v4):NULL;
616                                 } else {
617                                         v1= (me->mvert+mface->v1)->co;
618                                         v2= (me->mvert+mface->v2)->co;
619                                         v3= (me->mvert+mface->v3)->co;
620                                         v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
621                                 }
622         
623                                 glBegin(v4?GL_QUADS:GL_TRIANGLES);
624                                         glVertex3fv( v1 );
625                                         glVertex3fv( v2 );
626                                         glVertex3fv( v3 );
627                                         if(v4) glVertex3fv( v4 );
628                                 glEnd();
629                         }
630                 }
631                 glDisable(GL_BLEND);
632         }
633         
634         /* Draw Stippled Outline for selected faces */
635         mface= me->mface;
636         tface= me->tface;
637         bglPolygonOffset(1.0);
638         for(a=me->totface; a>0; a--, mface++, tface++) {
639                 if(mface->v3==0) continue;
640                 if(tface->flag & TF_HIDE) continue;
641                 
642                 if(tface->flag & (TF_ACTIVE|TF_SELECT) ) {
643                         if(extverts) {
644                                 v1= extverts+3*mface->v1;
645                                 v2= extverts+3*mface->v2;
646                                 v3= extverts+3*mface->v3;
647                                 v4= mface->v4?(extverts+3*mface->v4):NULL;
648                         } else {
649                                 v1= (me->mvert+mface->v1)->co;
650                                 v2= (me->mvert+mface->v2)->co;
651                                 v3= (me->mvert+mface->v3)->co;
652                                 v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
653                         }
654
655                         if(tface->flag & TF_ACTIVE) {
656                                 activeFaceInSelection= (tface->flag & TF_SELECT);
657                                 av1= v1; av2= v2; av3= v3; av4= v4;
658                         }
659                         else {
660                                 cpack(0x0);
661                                 glBegin(GL_LINE_LOOP);
662                                         glVertex3fv( v1 );
663                                         glVertex3fv( v2 );
664                                         glVertex3fv( v3 );
665                                         if(v4) glVertex3fv( v4 );
666                                 glEnd();
667                         }
668
669                         if(tface->flag & TF_SELECT) {
670                                 cpack(0xFFFFFF);
671                                 setlinestyle(1);
672                                 glBegin(GL_LINE_LOOP);
673                                         glVertex3fv( v1 );
674                                         glVertex3fv( v2 );
675                                         glVertex3fv( v3 );
676                                         if(v4) glVertex3fv( v4 );
677                                 glEnd();
678                                 setlinestyle(0);
679                         }
680                 }
681         }
682
683         /* Draw Active Face on top */
684         /* colors: R=x G=y */
685         if(av1) {
686                 cpack(0xFF);
687                 glBegin(GL_LINE_STRIP);
688                         glVertex3fv(av1);
689                         if(av4) glVertex3fv(av4);
690                         else glVertex3fv(av3);
691                 glEnd();
692
693                 cpack(0xFF00);
694                 glBegin(GL_LINE_STRIP);
695                         glVertex3fv(av1);
696                         glVertex3fv(av2);
697                 glEnd();
698
699                 if(activeFaceInSelection) cpack(0x00FFFF);
700                 else cpack(0xFF00FF);
701
702                 glBegin(GL_LINE_STRIP);
703                         glVertex3fv(av2);
704                         glVertex3fv(av3);
705                         if(av4) glVertex3fv(av4);
706                 glEnd();
707                 setlinestyle(0);
708         }
709
710         bglPolygonOffset(0.0);  // resets correctly now, even after calling accumulated offsets
711 }
712
713 static int set_gl_light(Object *ob)
714 {
715         Base *base;
716         Lamp *la;
717         int count;
718         /* float zero[4]= {0.0, 0.0, 0.0, 0.0};  */
719         float vec[4];
720         
721         vec[3]= 1.0;
722         
723         for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
724         
725         count= 0;
726         
727         base= FIRSTBASE;
728         while(base) {
729                 if(base->object->type==OB_LAMP ) {
730                         if(base->lay & G.vd->lay) {
731                                 if(base->lay & ob->lay) 
732                                 {
733                                         la= base->object->data;
734                                         
735                                         glPushMatrix();
736                                         glLoadMatrixf((float *)G.vd->viewmat);
737                                         
738                                         where_is_object_simul(base->object);
739                                         VECCOPY(vec, base->object->obmat[3]);
740                                         
741                                         if(la->type==LA_SUN) {
742                                                 vec[0]= base->object->obmat[2][0];
743                                                 vec[1]= base->object->obmat[2][1];
744                                                 vec[2]= base->object->obmat[2][2];
745                                                 vec[3]= 0.0;
746                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
747                                         }
748                                         else {
749                                                 vec[3]= 1.0;
750                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
751                                                 glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
752                                                 glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
753                                                 /* post 2.25 engine supports quad lights */
754                                                 glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
755                                                 
756                                                 if(la->type==LA_SPOT) {
757                                                         vec[0]= -base->object->obmat[2][0];
758                                                         vec[1]= -base->object->obmat[2][1];
759                                                         vec[2]= -base->object->obmat[2][2];
760                                                         glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
761                                                         glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
762                                                         glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
763                                                 }
764                                                 else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
765                                         }
766                                         
767                                         vec[0]= la->energy*la->r;
768                                         vec[1]= la->energy*la->g;
769                                         vec[2]= la->energy*la->b;
770                                         vec[3]= 1.0;
771                                         glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec); 
772                                         glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero); 
773                                         glEnable(GL_LIGHT0+count);
774                                         
775                                         glPopMatrix();                                  
776                                         
777                                         count++;
778                                         if(count>7) break;
779                                 }
780                         }
781                 }
782                 base= base->next;
783         }
784
785         return count;
786 }
787
788 static Material *give_current_material_or_def(Object *ob, int matnr)
789 {
790         extern Material defmaterial;    // render module abuse...
791         Material *ma= give_current_material(ob, matnr);
792
793         return ma?ma:&defmaterial;
794 }
795
796 static int set_draw_settings_cached(int clearcache, int textured, TFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
797 {
798         static int c_textured;
799         static int c_lit;
800         static int c_doublesided;
801         static TFace *c_texface;
802         static Object *c_litob;
803         static int c_litmatnr;
804         static int c_badtex;
805
806         if (clearcache) {
807                 c_textured= c_lit= c_doublesided= -1;
808                 c_texface= (TFace*) -1;
809                 c_litob= (Object*) -1;
810                 c_litmatnr= -1;
811                 c_badtex= 0;
812         }
813
814         if (texface) {
815                 lit = lit && (texface->mode&TF_LIGHT);
816                 textured = textured && (texface->mode&TF_TEX);
817                 doublesided = texface->mode&TF_TWOSIDE;
818         } else {
819                 textured = 0;
820         }
821
822         if (doublesided!=c_doublesided) {
823                 if (doublesided) glDisable(GL_CULL_FACE);
824                 else glEnable(GL_CULL_FACE);
825
826                 c_doublesided= doublesided;
827         }
828
829         if (textured!=c_textured || texface!=c_texface) {
830                 if (textured ) {
831                         c_badtex= !set_tpage(texface);
832                 } else {
833                         set_tpage(0);
834                         c_badtex= 0;
835                 }
836                 c_textured= textured;
837                 c_texface= texface;
838         }
839
840         if (c_badtex) lit= 0;
841         if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
842                 if (lit) {
843                         Material *ma= give_current_material_or_def(litob, litmatnr);
844                         float spec[4];
845
846                         spec[0]= ma->spec*ma->specr;
847                         spec[1]= ma->spec*ma->specg;
848                         spec[2]= ma->spec*ma->specb;
849                         spec[3]= 1.0;
850
851                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
852                         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
853                         glEnable(GL_LIGHTING);
854                         glEnable(GL_COLOR_MATERIAL);
855                 }
856                 else {
857                         glDisable(GL_LIGHTING); 
858                         glDisable(GL_COLOR_MATERIAL);
859                 }
860                 c_lit= lit;
861                 c_litob= litob;
862                 c_litmatnr= litmatnr;
863         }
864
865         return c_badtex;
866 }
867
868 /* Icky globals, fix with userdata parameter */
869
870 static Object *g_draw_tface_mesh_ob = NULL;
871 static int g_draw_tface_mesh_islight = 0;
872 static int g_draw_tface_mesh_istex = 0;
873 static unsigned char g_draw_tface_mesh_obcol[4];
874 static int draw_tface_mesh__set_draw(TFace *tface, int matnr)
875 {
876         if (set_draw_settings_cached(0, g_draw_tface_mesh_istex, tface, g_draw_tface_mesh_islight, g_draw_tface_mesh_ob, matnr, TF_TWOSIDE)) {
877                 glColor3ub(0xFF, 0x00, 0xFF);
878                 return 0; /* Don't set color */
879         } else if (tface && tface->mode&TF_OBCOL) {
880                 glColor3ubv(g_draw_tface_mesh_obcol);
881                 return 0; /* Don't set color */
882         } else if (!tface) {
883                 Material *ma= give_current_material(g_draw_tface_mesh_ob, matnr);
884                 if(ma) glColor3f(ma->r, ma->g, ma->b);
885                 else glColor3f(0.5, 0.5, 0.5);
886                 return 1; /* Set color from mcol if available */
887         } else {
888                 return 1; /* Set color from tface */
889         }
890 }
891 void draw_tface_mesh(Object *ob, Mesh *me, int dt)
892 /* maximum dt (drawtype): exactly according values that have been set */
893 {
894         TFace *tface=NULL;
895         MFace *mface=NULL;
896         float *extverts= NULL;
897         unsigned char obcol[4];
898         int a;
899         short islight, istex;
900         
901         if(me==NULL) return;
902
903
904         glShadeModel(GL_SMOOTH);
905
906         islight= set_gl_light(ob);
907         
908         obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
909         obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
910         obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
911         obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
912         
913         /* first all texture polys */
914         
915         if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
916         else glFrontFace(GL_CCW);
917         
918         glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
919         if(G.vd->drawtype==OB_TEXTURE) istex= 1;
920         else istex= 0;
921
922         g_draw_tface_mesh_ob = ob;
923         g_draw_tface_mesh_islight = islight;
924         g_draw_tface_mesh_istex = istex;
925         memcpy(g_draw_tface_mesh_obcol, obcol, sizeof(obcol));
926         set_draw_settings_cached(1, 0, 0, 0, 0, 0, 0);
927
928         if(dt > OB_SOLID) {
929                 bProperty *prop = get_property(ob, "Text");
930                 int editing= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));
931                 DerivedMesh *dm;
932                 int start, totface;
933
934                 if(mesh_uses_displist(me) && editing==0) {
935                         dm = mesh_get_derived(ob);
936                         dm->drawFacesTex(dm, draw_tface_mesh__set_draw);
937                 } else {
938                         dm = mesh_get_base_derived(ob);
939                         dm->drawFacesTex(dm, draw_tface_mesh__set_draw);
940                         dm->release(dm);
941                 }
942
943                 start = 0;
944                 totface = me->totface;
945                 set_buildvars(ob, &start, &totface);
946
947                 if (!editing && !mesh_uses_displist(me) && prop && tface) {
948                         tface+= start;
949                         for (a=start; a<totface; a++, tface++) {
950                                 MFace *mf= &mface[a];
951                                 int mode= tface->mode;
952                                 int matnr= mf->mat_nr;
953                                 int mf_smooth= mf->flag & ME_SMOOTH;
954
955                                 if (mf->v3 && !(tface->flag&TF_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
956                                         int badtex= set_draw_settings_cached(0, g_draw_tface_mesh_istex, tface, g_draw_tface_mesh_islight, g_draw_tface_mesh_ob, matnr, TF_TWOSIDE);
957                                         float *v1, *v2, *v3, *v4;
958                                         char string[MAX_PROPSTRING];
959                                         int characters, index;
960                                         Image *ima;
961                                         float curpos;
962
963                                         if (badtex)
964                                                 continue;
965
966                                         if (extverts) {
967                                                 v1= extverts+3*mf->v1;
968                                                 v2= extverts+3*mf->v2;
969                                                 v3= extverts+3*mf->v3;
970                                                 v4= mf->v4?(extverts+3*mf->v4):NULL;
971                                         } else {
972                                                 v1= (me->mvert+mf->v1)->co;
973                                                 v2= (me->mvert+mf->v2)->co;
974                                                 v3= (me->mvert+mf->v3)->co;
975                                                 v4= mf->v4?(me->mvert+mf->v4)->co:NULL;
976                                         }
977
978                                         // The BM_FONT handling code is duplicated in the gameengine
979                                         // Search for 'Frank van Beek' ;-)
980                                         // string = "Frank van Beek";
981
982                                         set_property_valstr(prop, string);
983                                         characters = strlen(string);
984                                         
985                                         ima = tface->tpage;
986                                         if (ima == NULL) {
987                                                 characters = 0;
988                                         }
989
990                                         if (1 || !mf_smooth) {
991                                                 float nor[3];
992
993                                                 CalcNormFloat(v1, v2, v3, nor);
994
995                                                 glNormal3fv(nor);
996                                         }
997
998                                         curpos= 0.0;
999                                         glBegin(v4?GL_QUADS:GL_TRIANGLES);
1000                                         for (index = 0; index < characters; index++) {
1001                                                 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
1002                                                 int character = string[index];
1003                                                 char *cp= NULL;
1004
1005                                                 // lets calculate offset stuff
1006                                                 // space starts at offset 1
1007                                                 // character = character - ' ' + 1;
1008                                                 
1009                                                 matrixGlyph(ima->ibuf, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
1010                                                 movex+= curpos;
1011
1012                                                 if (tface->mode & TF_OBCOL) glColor3ubv(obcol);
1013                                                 else cp= (char *)&(tface->col[0]);
1014
1015                                                 glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
1016                                                 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
1017                                                 glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
1018                                                 
1019                                                 glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
1020                                                 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
1021                                                 glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
1022                         
1023                                                 glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
1024                                                 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
1025                                                 glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
1026                         
1027                                                 if(v4) {
1028                                                         glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
1029                                                         if (cp) glColor3ub(cp[15], cp[14], cp[13]);
1030                                                         glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
1031                                                 }
1032
1033                                                 curpos+= advance;
1034                                         }
1035                                         glEnd();
1036                                 }
1037                         }
1038                 }
1039
1040                 /* switch off textures */
1041                 set_tpage(0);
1042         }
1043         glShadeModel(GL_FLAT);
1044         glDisable(GL_CULL_FACE);
1045         
1046         if(ob==OBACT && (G.f & G_FACESELECT)) {
1047                 draw_tfaces3D(ob, me);
1048         }
1049         
1050                 /* XXX, bad patch - default_gl_light() calls
1051                  * glLightfv(GL_LIGHT_POSITION, ...) which
1052                  * is transformed by the current matrix... we
1053                  * need to make sure that matrix is identity.
1054                  * 
1055                  * It would be better if drawmesh.c kept track
1056                  * of and restored the light settings it changed.
1057                  *  - zr
1058                  */
1059         glPushMatrix();
1060         glLoadIdentity();       
1061         default_gl_light();
1062         glPopMatrix();
1063         
1064         glFrontFace(GL_CCW);
1065
1066 }
1067
1068 void init_realtime_GL(void)
1069 {               
1070         glMatrixMode(GL_TEXTURE);
1071         glLoadIdentity();
1072         glMatrixMode(GL_MODELVIEW);
1073
1074 }
1075