- added DerivedMesh.drawUVEdges function & implementations
[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         tag_image_time(ima);
421
422         glEnable(GL_TEXTURE_2D);
423
424         fCurpage= ima;
425         fCurmode= tilemode;
426         fCurtileXRep = tileXRep;
427         fCurtileYRep = tileYRep;
428
429         return 1;
430 }
431
432 void free_realtime_image(Image *ima)
433 {
434         if(ima->bindcode) {
435                 glDeleteTextures(1, (GLuint *)&ima->bindcode);
436                 ima->bindcode= 0;
437         }
438         if(ima->repbind) {
439                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
440         
441                 MEM_freeN(ima->repbind);
442                 ima->repbind= 0;
443         }
444 }
445
446 void free_all_realtime_images(void)
447 {
448         Image* ima;
449
450         ima= G.main->image.first;
451         while(ima) {
452                 free_realtime_image(ima);
453                 ima= ima->id.next;
454         }
455 }
456
457 void make_repbind(Image *ima)
458 {
459         if(ima==0 || ima->ibuf==0) return;
460
461         if(ima->repbind) {
462                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
463                 MEM_freeN(ima->repbind);
464                 ima->repbind= 0;
465         }
466         ima->totbind= ima->xrep*ima->yrep;
467         if(ima->totbind>1) {
468                 ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
469         }
470 }
471
472 void update_realtime_textures()
473 {
474         Image *ima;
475         
476         ima= G.main->image.first;
477         while(ima) {
478                 if(ima->tpageflag & IMA_TWINANIM) {
479                         if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
480                 
481                         /* check: is bindcode not in the array? Free. (to do) */
482                         
483                         ima->lastframe++;
484                         if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
485                         
486                 }
487                 ima= ima->id.next;
488         }
489 }
490
491
492 static int draw_tfaces3D__drawFaceOpts(TFace *tface, int matnr)
493 {
494         if (tface && !(tface->flag&TF_HIDE) && (tface->flag&TF_SELECT)) {
495                 return 2; /* Don't set color */
496         } else {
497                 return 0;
498         }
499 }
500 static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
501 {
502         int a;
503
504         glEnable(GL_DEPTH_TEST);
505         glDisable(GL_LIGHTING);
506         bglPolygonOffset(1.0);
507
508                 /* Draw (Hidden) Edges */
509         BIF_ThemeColor(TH_EDGE_FACESEL);
510         if((G.f & G_DRAWEDGES)){ 
511                 if (G.f&G_HIDDENEDGES) {
512                         dm->drawEdgesFlag(dm, ME_EDGEMAPPED, ME_EDGEMAPPED);
513                 } else {
514                         dm->drawEdgesFlag(dm, ME_EDGE_TFVISIBLE, ME_EDGE_TFVISIBLE);
515                 }
516         } else {
517                 dm->drawEdgesFlag(dm, ME_EDGE_TFVISIBLE|ME_EDGE_TFSEL, ME_EDGE_TFVISIBLE|ME_EDGE_TFSEL);
518         }
519
520         if(G.f & G_DRAWSEAMS) {
521                 BIF_ThemeColor(TH_EDGE_SEAM);
522                 glLineWidth(2);
523
524                 if (G.f&G_HIDDENEDGES) {
525                         dm->drawEdgesFlag(dm, ME_EDGEMAPPED|ME_SEAM, ME_EDGEMAPPED|ME_SEAM);
526                 } else {
527                         dm->drawEdgesFlag(dm, ME_EDGE_TFVISIBLE|ME_SEAM, ME_EDGE_TFVISIBLE|ME_SEAM);
528                 }
529
530                 glLineWidth(1);
531         }
532
533         /* Draw Selected Faces in transparent purple */
534         if(G.f & G_DRAWFACES) {
535                 glEnable(GL_BLEND);
536                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
537                 BIF_ThemeColor4(TH_FACE_SELECT);
538
539                 dm->drawFacesTex(dm, draw_tfaces3D__drawFaceOpts);
540
541                 glDisable(GL_BLEND);
542         }
543         
544         bglPolygonOffset(1.0);
545
546                 /* Draw Stippled Outline for selected faces */
547         cpack(0xFFFFFF);
548         setlinestyle(1);
549         dm->drawEdgesFlag(dm, ME_EDGE_TFVISIBLE|ME_EDGE_TFSEL, ME_EDGE_TFVISIBLE|ME_EDGE_TFSEL);
550         setlinestyle(0);
551
552                 /* Draw active face */
553         for (a=0; a<me->totface; a++) {
554                 TFace *tf = &me->tface[a];
555
556                 if (me->mface[a].v3 && (tf->flag&TF_ACTIVE)) {
557                         if (!(tf->flag&TF_HIDE)) {
558                                 glColor3ub(255, 0, 0);
559                                 dm->drawEdgesFlag(dm, ME_EDGE_TFACTLAST, ME_EDGE_TFACTLAST);
560                                 glColor3ub(0, 255, 0);
561                                 dm->drawEdgesFlag(dm, ME_EDGE_TFACTFIRST, ME_EDGE_TFACTFIRST);
562
563                                 if (tf->flag&TF_SELECT) {
564                                         glColor3ub(255, 255, 0);
565                                 } else {
566                                         glColor3ub(255, 0, 255);
567                                 }
568
569                                         /* Draw remaining edges of active fact that are not first or last */
570                                 dm->drawEdgesFlag(dm, ME_EDGE_TFACT|ME_EDGE_TFACTFIRST|ME_EDGE_TFACTLAST, ME_EDGE_TFACT|0|0);
571                         }
572
573                         break;
574                 }
575         }
576
577         bglPolygonOffset(0.0);  // resets correctly now, even after calling accumulated offsets
578 #undef PASSVERT
579 }
580
581 static int set_gl_light(Object *ob)
582 {
583         Base *base;
584         Lamp *la;
585         int count;
586         /* float zero[4]= {0.0, 0.0, 0.0, 0.0};  */
587         float vec[4];
588         
589         vec[3]= 1.0;
590         
591         for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
592         
593         count= 0;
594         
595         base= FIRSTBASE;
596         while(base) {
597                 if(base->object->type==OB_LAMP ) {
598                         if(base->lay & G.vd->lay) {
599                                 if(base->lay & ob->lay) 
600                                 {
601                                         la= base->object->data;
602                                         
603                                         glPushMatrix();
604                                         glLoadMatrixf((float *)G.vd->viewmat);
605                                         
606                                         where_is_object_simul(base->object);
607                                         VECCOPY(vec, base->object->obmat[3]);
608                                         
609                                         if(la->type==LA_SUN) {
610                                                 vec[0]= base->object->obmat[2][0];
611                                                 vec[1]= base->object->obmat[2][1];
612                                                 vec[2]= base->object->obmat[2][2];
613                                                 vec[3]= 0.0;
614                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
615                                         }
616                                         else {
617                                                 vec[3]= 1.0;
618                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
619                                                 glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
620                                                 glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
621                                                 /* post 2.25 engine supports quad lights */
622                                                 glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
623                                                 
624                                                 if(la->type==LA_SPOT) {
625                                                         vec[0]= -base->object->obmat[2][0];
626                                                         vec[1]= -base->object->obmat[2][1];
627                                                         vec[2]= -base->object->obmat[2][2];
628                                                         glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
629                                                         glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
630                                                         glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
631                                                 }
632                                                 else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
633                                         }
634                                         
635                                         vec[0]= la->energy*la->r;
636                                         vec[1]= la->energy*la->g;
637                                         vec[2]= la->energy*la->b;
638                                         vec[3]= 1.0;
639                                         glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec); 
640                                         glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero); 
641                                         glEnable(GL_LIGHT0+count);
642                                         
643                                         glPopMatrix();                                  
644                                         
645                                         count++;
646                                         if(count>7) break;
647                                 }
648                         }
649                 }
650                 base= base->next;
651         }
652
653         return count;
654 }
655
656 static Material *give_current_material_or_def(Object *ob, int matnr)
657 {
658         extern Material defmaterial;    // render module abuse...
659         Material *ma= give_current_material(ob, matnr);
660
661         return ma?ma:&defmaterial;
662 }
663
664 static int set_draw_settings_cached(int clearcache, int textured, TFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
665 {
666         static int c_textured;
667         static int c_lit;
668         static int c_doublesided;
669         static TFace *c_texface;
670         static Object *c_litob;
671         static int c_litmatnr;
672         static int c_badtex;
673
674         if (clearcache) {
675                 c_textured= c_lit= c_doublesided= -1;
676                 c_texface= (TFace*) -1;
677                 c_litob= (Object*) -1;
678                 c_litmatnr= -1;
679                 c_badtex= 0;
680         }
681
682         if (texface) {
683                 lit = lit && (texface->mode&TF_LIGHT);
684                 textured = textured && (texface->mode&TF_TEX);
685                 doublesided = texface->mode&TF_TWOSIDE;
686         } else {
687                 textured = 0;
688         }
689
690         if (doublesided!=c_doublesided) {
691                 if (doublesided) glDisable(GL_CULL_FACE);
692                 else glEnable(GL_CULL_FACE);
693
694                 c_doublesided= doublesided;
695         }
696
697         if (textured!=c_textured || texface!=c_texface) {
698                 if (textured ) {
699                         c_badtex= !set_tpage(texface);
700                 } else {
701                         set_tpage(0);
702                         c_badtex= 0;
703                 }
704                 c_textured= textured;
705                 c_texface= texface;
706         }
707
708         if (c_badtex) lit= 0;
709         if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
710                 if (lit) {
711                         Material *ma= give_current_material_or_def(litob, litmatnr);
712                         float spec[4];
713
714                         spec[0]= ma->spec*ma->specr;
715                         spec[1]= ma->spec*ma->specg;
716                         spec[2]= ma->spec*ma->specb;
717                         spec[3]= 1.0;
718
719                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
720                         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
721                         glEnable(GL_LIGHTING);
722                         glEnable(GL_COLOR_MATERIAL);
723                 }
724                 else {
725                         glDisable(GL_LIGHTING); 
726                         glDisable(GL_COLOR_MATERIAL);
727                 }
728                 c_lit= lit;
729                 c_litob= litob;
730                 c_litmatnr= litmatnr;
731         }
732
733         return c_badtex;
734 }
735
736 /* Icky globals, fix with userdata parameter */
737
738 static Object *g_draw_tface_mesh_ob = NULL;
739 static int g_draw_tface_mesh_islight = 0;
740 static int g_draw_tface_mesh_istex = 0;
741 static unsigned char g_draw_tface_mesh_obcol[4];
742 static int draw_tface_mesh__set_draw(TFace *tface, int matnr)
743 {
744         if (tface && ((tface->flag&TF_HIDE) || (tface->mode&TF_INVISIBLE))) return 0;
745
746         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)) {
747                 glColor3ub(0xFF, 0x00, 0xFF);
748                 return 2; /* Don't set color */
749         } else if (tface && tface->mode&TF_OBCOL) {
750                 glColor3ubv(g_draw_tface_mesh_obcol);
751                 return 2; /* Don't set color */
752         } else if (!tface) {
753                 Material *ma= give_current_material(g_draw_tface_mesh_ob, matnr);
754                 if(ma) glColor3f(ma->r, ma->g, ma->b);
755                 else glColor3f(0.5, 0.5, 0.5);
756                 return 1; /* Set color from mcol if available */
757         } else {
758                 return 1; /* Set color from tface */
759         }
760 }
761 void draw_tface_mesh(Object *ob, Mesh *me, int dt)
762 /* maximum dt (drawtype): exactly according values that have been set */
763 {
764         unsigned char obcol[4];
765         int a;
766         short islight, istex;
767         DerivedMesh *dm;
768         int dmNeedsFree;
769         
770         if(me==NULL) return;
771
772         dm = mesh_get_derived_final(ob, &dmNeedsFree);
773
774         glShadeModel(GL_SMOOTH);
775
776         islight= set_gl_light(ob);
777         
778         obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
779         obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
780         obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
781         obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
782         
783         /* first all texture polys */
784         
785         if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
786         else glFrontFace(GL_CCW);
787         
788         glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
789         if(G.vd->drawtype==OB_TEXTURE) istex= 1;
790         else istex= 0;
791
792         g_draw_tface_mesh_ob = ob;
793         g_draw_tface_mesh_islight = islight;
794         g_draw_tface_mesh_istex = istex;
795         memcpy(g_draw_tface_mesh_obcol, obcol, sizeof(obcol));
796         set_draw_settings_cached(1, 0, 0, 0, 0, 0, 0);
797
798         if(dt > OB_SOLID) {
799                 TFace *tface= me->tface;
800                 MFace *mface= me->mface;
801                 bProperty *prop = get_property(ob, "Text");
802                 int editing= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));
803                 int start, totface;
804
805                 dm->drawFacesTex(dm, draw_tface_mesh__set_draw);
806
807                 start = 0;
808                 totface = me->totface;
809
810                 if (!editing && prop && tface) {
811                         int dmNeedsFree;
812                         DerivedMesh *dm = mesh_get_derived_deform(ob, &dmNeedsFree);
813
814                         tface+= start;
815                         for (a=start; a<totface; a++, tface++) {
816                                 MFace *mf= &mface[a];
817                                 int mode= tface->mode;
818                                 int matnr= mf->mat_nr;
819                                 int mf_smooth= mf->flag & ME_SMOOTH;
820
821                                 if (mf->v3 && !(tface->flag&TF_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
822                                         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);
823                                         float v1[3], v2[3], v3[3], v4[3];
824                                         char string[MAX_PROPSTRING];
825                                         int characters, index;
826                                         Image *ima;
827                                         float curpos;
828
829                                         if (badtex)
830                                                 continue;
831
832                                         dm->getVertCo(dm, mf->v1, v1);
833                                         dm->getVertCo(dm, mf->v2, v2);
834                                         dm->getVertCo(dm, mf->v3, v3);
835                                         if (mf->v4) dm->getVertCo(dm, mf->v4, v4);
836
837                                         // The BM_FONT handling code is duplicated in the gameengine
838                                         // Search for 'Frank van Beek' ;-)
839                                         // string = "Frank van Beek";
840
841                                         set_property_valstr(prop, string);
842                                         characters = strlen(string);
843                                         
844                                         ima = tface->tpage;
845                                         if (ima == NULL) {
846                                                 characters = 0;
847                                         }
848
849                                         if (!mf_smooth) {
850                                                 float nor[3];
851
852                                                 CalcNormFloat(v1, v2, v3, nor);
853
854                                                 glNormal3fv(nor);
855                                         }
856
857                                         curpos= 0.0;
858                                         glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
859                                         for (index = 0; index < characters; index++) {
860                                                 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
861                                                 int character = string[index];
862                                                 char *cp= NULL;
863
864                                                 // lets calculate offset stuff
865                                                 // space starts at offset 1
866                                                 // character = character - ' ' + 1;
867                                                 
868                                                 matrixGlyph(ima->ibuf, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
869                                                 movex+= curpos;
870
871                                                 if (tface->mode & TF_OBCOL) glColor3ubv(obcol);
872                                                 else cp= (char *)&(tface->col[0]);
873
874                                                 glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
875                                                 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
876                                                 glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
877                                                 
878                                                 glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
879                                                 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
880                                                 glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
881                         
882                                                 glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
883                                                 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
884                                                 glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
885                         
886                                                 if(mf->v4) {
887                                                         glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
888                                                         if (cp) glColor3ub(cp[15], cp[14], cp[13]);
889                                                         glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
890                                                 }
891
892                                                 curpos+= advance;
893                                         }
894                                         glEnd();
895                                 }
896                         }
897
898                         if (dmNeedsFree) dm->release(dm);
899                 }
900
901                 /* switch off textures */
902                 set_tpage(0);
903         }
904         glShadeModel(GL_FLAT);
905         glDisable(GL_CULL_FACE);
906         
907         if(ob==OBACT && (G.f & G_FACESELECT) && me && me->tface) {
908                 draw_tfaces3D(ob, me, dm);
909         }
910         
911                 /* XXX, bad patch - default_gl_light() calls
912                  * glLightfv(GL_LIGHT_POSITION, ...) which
913                  * is transformed by the current matrix... we
914                  * need to make sure that matrix is identity.
915                  * 
916                  * It would be better if drawmesh.c kept track
917                  * of and restored the light settings it changed.
918                  *  - zr
919                  */
920         glPushMatrix();
921         glLoadIdentity();       
922         default_gl_light();
923         glPopMatrix();
924         
925         glFrontFace(GL_CCW);
926
927 }
928
929 void init_realtime_GL(void)
930 {               
931         glMatrixMode(GL_TEXTURE);
932         glLoadIdentity();
933         glMatrixMode(GL_MODELVIEW);
934
935 }
936