Two in one:
[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 #include "BLI_edgehash.h"
45
46 #include "IMB_imbuf.h"
47 #include "IMB_imbuf_types.h"
48
49 #include "DNA_image_types.h"
50 #include "DNA_lamp_types.h"
51 #include "DNA_material_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_property_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_view3d_types.h"
58
59 #include "BKE_bmfont.h"
60 #include "BKE_displist.h"
61 #include "BKE_DerivedMesh.h"
62 #include "BKE_effect.h"
63 #include "BKE_global.h"
64 #include "BKE_image.h"
65 #include "BKE_main.h"
66 #include "BKE_material.h"
67 #include "BKE_mesh.h"
68 #include "BKE_object.h"
69 #include "BKE_property.h"
70 #include "BKE_utildefines.h"
71
72 #include "BIF_resources.h"
73 #include "BIF_gl.h"
74 #include "BIF_glutil.h"
75 #include "BIF_mywindow.h"
76 #include "BIF_resources.h"
77
78 #include "BDR_editface.h"
79 #include "BDR_vpaint.h"
80 #include "BDR_drawmesh.h"
81
82 #include "BSE_drawview.h"
83
84 #include "blendef.h"
85 #include "nla.h"
86
87 //#include "glext.h"
88 /* some local functions */
89 #if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__) && !defined(__linux__) && !defined(WIN32)
90         #define glBindTexture(A,B)     glBindTextureEXT(A,B)
91         #define glGenTextures(A,B)     glGenTexturesEXT(A,B)
92         #define glDeleteTextures(A,B)  glDeleteTexturesEXT(A,B)
93         #define glPolygonOffset(A,B)  glPolygonOffsetEXT(A,B)
94
95 #else
96
97 /* #define GL_FUNC_ADD_EXT                                      GL_FUNC_ADD */
98 /* #define GL_FUNC_REVERSE_SUBTRACT_EXT GL_FUNC_REVERSE_SUBTRACT */
99 /* #define GL_POLYGON_OFFSET_EXT                        GL_POLYGON_OFFSET */
100
101 #endif
102
103         /* (n&(n-1)) zeros the least significant bit of n */
104 static int is_pow2(int num) {
105         return ((num)&(num-1))==0;
106 }
107 static int smaller_pow2(int num) {
108         while (!is_pow2(num))
109                 num= num&(num-1);
110         return num;     
111 }
112
113 static int fCurtile=0, fCurmode=0,fCurtileXRep=0,fCurtileYRep=0;
114 static Image *fCurpage=0;
115 static short fTexwindx, fTexwindy, fTexwinsx, fTexwinsy;
116 static int fDoMipMap = 1;
117 static int fLinearMipMap = 0;
118
119 /* local prototypes --------------- */
120 void update_realtime_textures(void);
121
122
123 /*  static int source, dest; also not used */
124
125 /**
126  * Enables or disable mipmapping for realtime images.
127  * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
128  */
129 void set_mipmap(int mipmap)
130 {
131         if (fDoMipMap != (mipmap != 0)) {
132                 free_all_realtime_images();
133                 fDoMipMap = mipmap != 0;
134         }
135 }
136
137 /**
138  * Returns the current setting for mipmapping.
139  */
140 static int get_mipmap(void)
141 {
142         return fDoMipMap && (!(G.f & G_TEXTUREPAINT));
143 }
144
145 /**
146  * Enables or disable linear mipmap setting for realtime images (textures).
147  * Note that this will will destroy all texture bindings in OpenGL.
148  * @see free_realtime_image()
149  * @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0).
150  */
151 void set_linear_mipmap(int linear)
152 {
153         if (fLinearMipMap != (linear != 0)) {
154                 free_all_realtime_images();
155                 fLinearMipMap = linear != 0;
156         }
157 }
158
159 /**
160  * Returns the current setting for linear mipmapping.
161  */
162 int get_linear_mipmap(void)
163 {
164         return fLinearMipMap;
165 }
166
167
168 /**
169  * Resets the realtime image cache variables.
170  */
171 void clear_realtime_image_cache()
172 {
173         fCurpage = NULL;
174         fCurtile = 0;
175         fCurmode = 0;
176         fCurtileXRep = 0;
177         fCurtileYRep = 0;
178 }
179
180 /* REMEMBER!  Changes here must go into my_set_tpage() as well */
181 int set_tpage(MTFace *tface)
182 {       
183         static int alphamode= -1;
184         static MTFace *lasttface= 0;
185         Image *ima;
186         ImBuf *ibuf;
187         unsigned int *rect=NULL, *bind;
188         int tpx=0, tpy=0, tilemode, tileXRep,tileYRep;
189         
190         /* disable */
191         if(tface==0) {
192                 if(lasttface==0) return 0;
193                 
194                 lasttface= 0;
195                 fCurtile= 0;
196                 fCurpage= 0;
197                 if(fCurmode!=0) {
198                         glMatrixMode(GL_TEXTURE);
199                         glLoadIdentity();
200                         glMatrixMode(GL_MODELVIEW);
201                 }
202                 fCurmode= 0;
203                 fCurtileXRep=0;
204                 fCurtileYRep=0;
205                 alphamode= -1;
206                 
207                 glDisable(GL_BLEND);
208                 glDisable(GL_TEXTURE_2D);
209                 glDisable(GL_TEXTURE_GEN_S);
210                 glDisable(GL_TEXTURE_GEN_T);
211
212                 return 0;
213         }
214         lasttface= tface;
215
216         if( alphamode != tface->transp) {
217                 alphamode= tface->transp;
218
219                 if(alphamode) {
220                         glEnable(GL_BLEND);
221                         
222                         if(alphamode==TF_ADD) {
223                                 glBlendFunc(GL_ONE, GL_ONE);
224                         /*      glBlendEquationEXT(GL_FUNC_ADD_EXT); */
225                         }
226                         else if(alphamode==TF_ALPHA) {
227                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
228                         /*      glBlendEquationEXT(GL_FUNC_ADD_EXT); */
229                         }
230                         /* else { */
231                         /*      glBlendFunc(GL_ONE, GL_ONE); */
232                         /*      glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
233                         /* } */
234                 }
235                 else glDisable(GL_BLEND);
236         }
237
238         ima= tface->tpage;
239
240         /* Enable or disable reflection mapping */
241         if (ima && (ima->flag & IMA_REFLECT)){
242
243 //              glActiveTextureARB(GL_TEXTURE0_ARB);
244                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
245                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
246
247                 glEnable(GL_TEXTURE_GEN_S);
248                 glEnable(GL_TEXTURE_GEN_T);
249
250                 /* Handle multitexturing here */
251         }
252         else{
253                 glDisable(GL_TEXTURE_GEN_S);
254                 glDisable(GL_TEXTURE_GEN_T);
255         }
256
257         tilemode= tface->mode & TF_TILES;
258         tileXRep = 0;
259         tileYRep = 0;
260         if (ima) {
261                 tileXRep = ima->xrep;
262                 tileYRep = ima->yrep;
263         }
264
265
266         if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurtileXRep==tileXRep && fCurtileYRep == tileYRep) return ima!=0;
267
268         if(tilemode!=fCurmode || fCurtileXRep!=tileXRep || fCurtileYRep != tileYRep) {
269                 glMatrixMode(GL_TEXTURE);
270                 glLoadIdentity();
271                 
272                 if(tilemode && ima!=NULL)
273                         glScalef(ima->xrep, ima->yrep, 1.0);
274
275                 glMatrixMode(GL_MODELVIEW);
276         }
277
278         if(ima==NULL || 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         ibuf= BKE_image_get_ibuf(ima, NULL);
291         if(ibuf==NULL) {
292
293                 fCurtile= tface->tile;
294                 fCurpage= 0;
295                 fCurmode= tilemode;
296                 fCurtileXRep = tileXRep;
297                 fCurtileYRep = tileYRep;
298                 
299                 glDisable(GL_TEXTURE_2D);
300                 return 0;
301         }
302
303         if ((ibuf->rect==NULL) && ibuf->rect_float)
304                 IMB_rect_from_float(ibuf);
305
306         if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
307         else fCurtile= tface->tile;
308
309         if(tilemode) {
310
311                 if(ima->repbind==0) make_repbind(ima);
312                 
313                 if(fCurtile>=ima->totbind) fCurtile= 0;
314                 
315                 /* this happens when you change repeat buttons */
316                 if(ima->repbind) bind= ima->repbind+fCurtile;
317                 else bind= &ima->bindcode;
318                 
319                 if(*bind==0) {
320                         
321                         fTexwindx= ibuf->x/ima->xrep;
322                         fTexwindy= ibuf->y/ima->yrep;
323                         
324                         if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1;
325         
326                         fTexwinsy= fCurtile / ima->xrep;
327                         fTexwinsx= fCurtile - fTexwinsy*ima->xrep;
328         
329                         fTexwinsx*= fTexwindx;
330                         fTexwinsy*= fTexwindy;
331         
332                         tpx= fTexwindx;
333                         tpy= fTexwindy;
334
335                         rect= ibuf->rect + fTexwinsy*ibuf->x + fTexwinsx;
336                 }
337         }
338         else {
339                 bind= &ima->bindcode;
340                 
341                 if(*bind==0) {
342                         tpx= ibuf->x;
343                         tpy= ibuf->y;
344                         rect= ibuf->rect;
345                 }
346         }
347
348         if(*bind==0) {
349                 int rectw= tpx, recth= tpy;
350                 unsigned int *tilerect= NULL, *scalerect= NULL;
351
352                 /*
353                  * Maarten:
354                  * According to Ton this code is not needed anymore. It was used only
355                  * in really old Blenders.
356                  * Reevan:
357                  * Actually it is needed for backwards compatibility.  Simpledemo 6 does not display correctly without it.
358                  */
359 #if 1
360                 if (tilemode) {
361                         int y;
362                                 
363                         tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
364                         for (y=0; y<recth; y++) {
365                                 unsigned int *rectrow= &rect[y*ibuf->x];
366                                 unsigned int *tilerectrow= &tilerect[y*rectw];
367                                         
368                                 memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
369                         }
370                                 
371                         rect= tilerect;
372                 }
373 #endif
374                 if (!is_pow2(rectw) || !is_pow2(recth)) {
375                         rectw= smaller_pow2(rectw);
376                         recth= smaller_pow2(recth);
377                         
378                         scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
379                         gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
380                         rect= scalerect;
381                 }
382
383                 glGenTextures(1, (GLuint *)bind);
384                 
385                 if((G.f & G_DEBUG) || !*bind) {
386                         GLenum error = glGetError();
387                         printf("Texture: %s\n", ima->id.name+2);
388                         printf("name: %d, tpx: %d\n", *bind, tpx);
389                         printf("tile: %d, mode: %d\n", fCurtile, tilemode);
390                         if (error)
391                                 printf("error: %s\n", gluErrorString(error));
392                 }
393                 glBindTexture( GL_TEXTURE_2D, *bind);
394
395                 if (!get_mipmap())
396                 {
397                         glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
398                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
399                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
400                 } else
401                 {
402                         int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
403
404                         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
405                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
406                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
407
408                         ima->tpageflag |= IMA_MIPMAP_COMPLETE;
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 update_realtime_image(Image *ima, int x, int y, int w, int h)
431 {
432         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
433         
434         if (ima->repbind || get_mipmap() || !ima->bindcode || !ibuf ||
435                 (!is_pow2(ibuf->x) || !is_pow2(ibuf->y)) ||
436                 (w == 0) || (h == 0)) {
437                 /* these special cases require full reload still */
438                 free_realtime_image(ima);
439         }
440         else {
441                 int row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
442                 int skip_pixels = glaGetOneInteger(GL_UNPACK_SKIP_PIXELS);
443                 int skip_rows = glaGetOneInteger(GL_UNPACK_SKIP_ROWS);
444
445                 if ((ibuf->rect==NULL) && ibuf->rect_float)
446                         IMB_rect_from_float(ibuf);
447
448                 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
449
450                 glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
451                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
452                 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
453
454                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
455                         GL_UNSIGNED_BYTE, ibuf->rect);
456
457                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
458                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
459                 glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
460
461                 if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
462                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
463         }
464 }
465
466 void free_realtime_image(Image *ima)
467 {
468         if(ima->bindcode) {
469                 glDeleteTextures(1, (GLuint *)&ima->bindcode);
470                 ima->bindcode= 0;
471                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
472         }
473         if(ima->repbind) {
474                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
475         
476                 MEM_freeN(ima->repbind);
477                 ima->repbind= NULL;
478                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
479         }
480 }
481
482 void free_all_realtime_images(void)
483 {
484         Image* ima;
485
486         for(ima=G.main->image.first; ima; ima=ima->id.next)
487                 free_realtime_image(ima);
488 }
489
490 /* these two functions are called on entering and exiting texture paint mode,
491    temporary disabling/enabling mipmapping on all images for quick texture
492    updates with glTexSubImage2D. images that didn't change don't have to be
493    re-uploaded to OpenGL */
494 void texpaint_disable_mipmap(void)
495 {
496         Image* ima;
497         
498         if(!fDoMipMap)
499                 return;
500
501         for(ima=G.main->image.first; ima; ima=ima->id.next) {
502                 if(ima->bindcode) {
503                         glBindTexture(GL_TEXTURE_2D, ima->bindcode);
504                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
505                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
506                 }
507         }
508 }
509
510 void texpaint_enable_mipmap(void)
511 {
512         Image* ima;
513
514         if(!fDoMipMap)
515                 return;
516
517         for(ima=G.main->image.first; ima; ima=ima->id.next) {
518                 if(ima->bindcode) {
519                         if(ima->tpageflag & IMA_MIPMAP_COMPLETE) {
520                                 int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
521
522                                 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
523                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
524                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
525                         }
526                         else
527                                 free_realtime_image(ima);
528                 }
529         }
530 }
531
532 void make_repbind(Image *ima)
533 {
534         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
535         
536         if(ibuf==NULL) return;
537
538         if(ima->repbind) {
539                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
540                 MEM_freeN(ima->repbind);
541                 ima->repbind= 0;
542                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
543         }
544         ima->totbind= ima->xrep*ima->yrep;
545         if(ima->totbind>1) {
546                 ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
547         }
548 }
549
550 void update_realtime_textures()
551 {
552         Image *ima;
553         
554         ima= G.main->image.first;
555         while(ima) {
556                 if(ima->tpageflag & IMA_TWINANIM) {
557                         if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
558                 
559                         /* check: is bindcode not in the array? Free. (to do) */
560                         
561                         ima->lastframe++;
562                         if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
563                         
564                 }
565                 ima= ima->id.next;
566         }
567 }
568
569 /***/
570
571         /* Flags for marked edges */
572 enum {
573         eEdge_Visible = (1<<0),
574         eEdge_Select = (1<<1),
575         eEdge_Active = (1<<2),
576         eEdge_SelectAndActive = (1<<3),
577         eEdge_ActiveFirst = (1<<4),
578         eEdge_ActiveLast = (1<<5)
579 };
580
581         /* Creates a hash of edges to flags indicating
582          * adjacent tface select/active/etc flags.
583          */
584 static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
585 {
586         int *flags_p;
587
588         if (!BLI_edgehash_haskey(eh, v0, v1)) {
589                 BLI_edgehash_insert(eh, v0, v1, 0);
590         }
591
592         flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
593         *flags_p |= flags;
594 }
595
596 EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
597 {
598         EdgeHash *eh = BLI_edgehash_new();
599         int i;
600
601         for (i=0; i<me->totface; i++) {
602                 MFace *mf = &me->mface[i];
603                 MTFace *tf = &me->mtface[i];
604                 
605                 if (mf->v3) {
606                         if (!(tf->flag&TF_HIDE)) {
607                                 unsigned int flags = eEdge_Visible;
608                                 if (tf->flag&TF_SELECT) flags |= eEdge_Select;
609                                 if (tf->flag&TF_ACTIVE) {
610                                         flags |= eEdge_Active;
611                                         if (tf->flag&TF_SELECT) flags |= eEdge_SelectAndActive;
612                                 }
613
614                                 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
615                                 get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
616                                 if (mf->v4) {
617                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
618                                         get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
619                                 } else {
620                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
621                                 }
622
623                                 if (tf->flag&TF_ACTIVE) {
624                                         get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, eEdge_ActiveFirst);
625                                         get_marked_edge_info__orFlags(eh, mf->v1, mf->v4?mf->v4:mf->v3, eEdge_ActiveLast);
626                                 }
627                         }
628                 }
629         }
630
631         return eh;
632 }
633
634
635 static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
636 {
637         struct { Mesh *me; EdgeHash *eh; } *data = userData;
638         MEdge *med = &data->me->medge[index];
639         unsigned int flags = (int) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
640
641         if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) {
642                 return 0;
643         } else if(G.f & G_DRAWEDGES){ 
644                 if (G.f&G_HIDDENEDGES) {
645                         return 1;
646                 } else {
647                         return (flags & eEdge_Visible);
648                 }
649         } else {
650                 return (flags & eEdge_Select);
651         }
652 }
653 static int draw_tfaces3D__setSeamOpts(void *userData, int index)
654 {
655         struct { Mesh *me; EdgeHash *eh; } *data = userData;
656         MEdge *med = &data->me->medge[index];
657         unsigned int flags = (int) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
658
659         if (med->flag&ME_SEAM) {
660                 if (G.f&G_HIDDENEDGES) {
661                         return 1;
662                 } else {
663                         return (flags & eEdge_Visible);
664                 }
665         } else {
666                 return 0;
667         }
668 }
669 static int draw_tfaces3D__setSelectOpts(void *userData, int index)
670 {
671         struct { Mesh *me; EdgeHash *eh; } *data = userData;
672         MEdge *med = &data->me->medge[index];
673         unsigned int flags = (int) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
674
675         return flags & eEdge_Select;
676 }
677 static int draw_tfaces3D__setActiveOpts(void *userData, int index)
678 {
679         struct { Mesh *me; EdgeHash *eh; } *data = userData;
680         MEdge *med = &data->me->medge[index];
681         unsigned int flags = (int) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
682
683         if (flags & eEdge_Active) {
684                 if (flags & eEdge_ActiveLast) {
685                         glColor3ub(255, 0, 0);
686                 } else if (flags & eEdge_ActiveFirst) {
687                         glColor3ub(0, 255, 0);
688                 } else if (flags & eEdge_SelectAndActive) {
689                         glColor3ub(255, 255, 0);
690                 } else {
691                         glColor3ub(255, 0, 255);
692                 }
693
694                 return 1;
695         } else {
696                 return 0;
697         }
698 }
699 static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
700 {
701         Mesh *me = (Mesh*)userData;
702
703         if (me->mtface) {
704                 MTFace *tface = &me->mtface[index];
705                 if (!(tface->flag&TF_HIDE) && (tface->flag&TF_SELECT))
706                         return 2; /* Don't set color */
707                 else
708                         return 0;
709         } else
710                 return 0;
711 }
712 static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
713 {
714         struct { Mesh *me; EdgeHash *eh; } data;
715
716         data.me = me;
717         data.eh = get_tface_mesh_marked_edge_info(me);
718
719         glEnable(GL_DEPTH_TEST);
720         glDisable(GL_LIGHTING);
721         bglPolygonOffset(1.0);
722
723                 /* Draw (Hidden) Edges */
724         BIF_ThemeColor(TH_EDGE_FACESEL);
725         dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
726
727                 /* Draw Seams */
728         if(G.f & G_DRAWSEAMS) {
729                 BIF_ThemeColor(TH_EDGE_SEAM);
730                 glLineWidth(2);
731
732                 dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
733
734                 glLineWidth(1);
735         }
736
737                 /* Draw Selected Faces */
738         if(G.f & G_DRAWFACES) {
739                 glEnable(GL_BLEND);
740                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
741                 BIF_ThemeColor4(TH_FACE_SELECT);
742
743                 dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
744
745                 glDisable(GL_BLEND);
746         }
747         
748         bglPolygonOffset(1.0);
749
750                 /* Draw Stippled Outline for selected faces */
751         glColor3ub(255, 255, 255);
752         setlinestyle(1);
753         dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
754         setlinestyle(0);
755
756         dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
757
758         bglPolygonOffset(0.0);  // resets correctly now, even after calling accumulated offsets
759
760         BLI_edgehash_free(data.eh, NULL);
761 }
762
763 static int set_gl_light(Object *ob)
764 {
765         Base *base;
766         Lamp *la;
767         int count;
768         /* float zero[4]= {0.0, 0.0, 0.0, 0.0};  */
769         float vec[4];
770         
771         vec[3]= 1.0;
772         
773         for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
774         
775         count= 0;
776         
777         base= FIRSTBASE;
778         while(base) {
779                 if(base->object->type==OB_LAMP ) {
780                         if(base->lay & G.vd->lay) {
781                                 if(base->lay & ob->lay) 
782                                 {
783                                         la= base->object->data;
784                                         
785                                         glPushMatrix();
786                                         glLoadMatrixf((float *)G.vd->viewmat);
787                                         
788                                         where_is_object_simul(base->object);
789                                         VECCOPY(vec, base->object->obmat[3]);
790                                         
791                                         if(la->type==LA_SUN) {
792                                                 vec[0]= base->object->obmat[2][0];
793                                                 vec[1]= base->object->obmat[2][1];
794                                                 vec[2]= base->object->obmat[2][2];
795                                                 vec[3]= 0.0;
796                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
797                                         }
798                                         else {
799                                                 vec[3]= 1.0;
800                                                 glLightfv(GL_LIGHT0+count, GL_POSITION, vec); 
801                                                 glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
802                                                 glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
803                                                 /* post 2.25 engine supports quad lights */
804                                                 glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
805                                                 
806                                                 if(la->type==LA_SPOT) {
807                                                         vec[0]= -base->object->obmat[2][0];
808                                                         vec[1]= -base->object->obmat[2][1];
809                                                         vec[2]= -base->object->obmat[2][2];
810                                                         glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
811                                                         glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
812                                                         glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
813                                                 }
814                                                 else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
815                                         }
816                                         
817                                         vec[0]= la->energy*la->r;
818                                         vec[1]= la->energy*la->g;
819                                         vec[2]= la->energy*la->b;
820                                         vec[3]= 1.0;
821                                         glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec); 
822                                         glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero); 
823                                         glEnable(GL_LIGHT0+count);
824                                         
825                                         glPopMatrix();                                  
826                                         
827                                         count++;
828                                         if(count>7) break;
829                                 }
830                         }
831                 }
832                 base= base->next;
833         }
834
835         return count;
836 }
837
838 static Material *give_current_material_or_def(Object *ob, int matnr)
839 {
840         extern Material defmaterial;    // render module abuse...
841         Material *ma= give_current_material(ob, matnr);
842
843         return ma?ma:&defmaterial;
844 }
845
846 static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
847 {
848         static int c_textured;
849         static int c_lit;
850         static int c_doublesided;
851         static MTFace *c_texface;
852         static Object *c_litob;
853         static int c_litmatnr;
854         static int c_badtex;
855
856         if (clearcache) {
857                 c_textured= c_lit= c_doublesided= -1;
858                 c_texface= (MTFace*) -1;
859                 c_litob= (Object*) -1;
860                 c_litmatnr= -1;
861                 c_badtex= 0;
862         }
863
864         if (texface) {
865                 lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
866                 textured = textured && (texface->mode&TF_TEX);
867                 doublesided = texface->mode&TF_TWOSIDE;
868         } else {
869                 textured = 0;
870         }
871
872         if (doublesided!=c_doublesided) {
873                 if (doublesided) glDisable(GL_CULL_FACE);
874                 else glEnable(GL_CULL_FACE);
875
876                 c_doublesided= doublesided;
877         }
878
879         if (textured!=c_textured || texface!=c_texface) {
880                 if (textured ) {
881                         c_badtex= !set_tpage(texface);
882                 } else {
883                         set_tpage(0);
884                         c_badtex= 0;
885                 }
886                 c_textured= textured;
887                 c_texface= texface;
888         }
889
890         if (c_badtex) lit= 0;
891         if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
892                 if (lit) {
893                         Material *ma= give_current_material_or_def(litob, litmatnr+1);
894                         float spec[4];
895
896                         spec[0]= ma->spec*ma->specr;
897                         spec[1]= ma->spec*ma->specg;
898                         spec[2]= ma->spec*ma->specb;
899                         spec[3]= 1.0;
900
901                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
902                         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
903                         glEnable(GL_LIGHTING);
904                         glEnable(GL_COLOR_MATERIAL);
905                 }
906                 else {
907                         glDisable(GL_LIGHTING); 
908                         glDisable(GL_COLOR_MATERIAL);
909                 }
910                 c_lit= lit;
911                 c_litob= litob;
912                 c_litmatnr= litmatnr;
913         }
914
915         return c_badtex;
916 }
917
918 /* Icky globals, fix with userdata parameter */
919
920 static Object *g_draw_tface_mesh_ob = NULL;
921 static int g_draw_tface_mesh_islight = 0;
922 static int g_draw_tface_mesh_istex = 0;
923 static unsigned char g_draw_tface_mesh_obcol[4];
924
925 static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
926 {
927         if (tface && ((tface->flag&TF_HIDE) || (tface->mode&TF_INVISIBLE))) return 0;
928
929         if (tface && set_draw_settings_cached(0, g_draw_tface_mesh_istex, tface, g_draw_tface_mesh_islight, g_draw_tface_mesh_ob, matnr, TF_TWOSIDE)) {
930                 glColor3ub(0xFF, 0x00, 0xFF);
931                 return 2; /* Don't set color */
932         } else if (tface && tface->mode&TF_OBCOL) {
933                 glColor3ubv(g_draw_tface_mesh_obcol);
934                 return 2; /* Don't set color */
935         } else if (!mcol) {
936                 if (tface) glColor3f(1.0, 1.0, 1.0);
937                 else {
938                         Material *ma= give_current_material(g_draw_tface_mesh_ob, matnr+1);
939                         if(ma) glColor3f(ma->r, ma->g, ma->b);
940                         else glColor3f(1.0, 1.0, 1.0);
941                 }
942                 return 2; /* Don't set color */
943         } else {
944                 return 1; /* Set color from mcol */
945         }
946 }
947
948 static int draw_tface_mapped__set_draw(void *userData, int index)
949 {
950         Mesh *me = (Mesh*)userData;
951         MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
952         MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
953         int matnr = me->mface[index].mat_nr;
954
955         return draw_tface__set_draw(tface, mcol, matnr);
956 }
957
958 static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
959 {
960         MTFace *tface = (MTFace *)userData;
961         if (tface) {
962                 tface+= index;
963                 if ((tface->flag&TF_HIDE) || (tface->mode&TF_INVISIBLE)) 
964                         return 0;
965         }
966         *drawSmooth_r = 1;
967         return 1;
968 }
969
970 void draw_tface_mesh(Object *ob, Mesh *me, int dt)
971 /* maximum dt (drawtype): exactly according values that have been set */
972 {
973         unsigned char obcol[4];
974         int a;
975         short istex, solidtex=0;
976         DerivedMesh *dm;
977         
978         if(me==NULL) return;
979
980         dm = mesh_get_derived_final(ob, get_viewedit_datamask());
981
982         glShadeModel(GL_SMOOTH);
983
984         /* option to draw solid texture with default lights */
985         if(dt>OB_WIRE && G.vd->drawtype==OB_SOLID) {
986                 solidtex= 1;
987                 g_draw_tface_mesh_islight= -1;
988         }
989         else
990                 g_draw_tface_mesh_islight= set_gl_light(ob);
991         
992         obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
993         obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
994         obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
995         obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
996         
997         /* first all texture polys */
998         
999         if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
1000         else glFrontFace(GL_CCW);
1001         
1002         glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
1003         if(solidtex || G.vd->drawtype==OB_TEXTURE) istex= 1;
1004         else istex= 0;
1005
1006         g_draw_tface_mesh_ob = ob;
1007         g_draw_tface_mesh_istex = istex;
1008         memcpy(g_draw_tface_mesh_obcol, obcol, sizeof(obcol));
1009         set_draw_settings_cached(1, 0, 0, 0, 0, 0, 0);
1010
1011         if(dt > OB_SOLID || g_draw_tface_mesh_islight==-1) {
1012                 bProperty *prop = get_property(ob, "Text");
1013                 int editing= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));
1014
1015 #ifdef WITH_VERSE
1016                 if(me->vnode) {
1017                         /* verse-blender doesn't support uv mapping of textures yet */
1018                         dm->drawFacesTex(dm, NULL);
1019                 }
1020                 else if(ob==OBACT && (G.f & G_FACESELECT) && me && me->mtface) {
1021 #else
1022                 if(ob==OBACT && (G.f & G_FACESELECT) && me && me->mtface) {
1023 #endif          
1024                         if(G.f & G_WEIGHTPAINT)
1025                                 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mtface, 1);
1026                         else
1027                                 dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, (void*)me);
1028                 }
1029                 else
1030                         dm->drawFacesTex(dm, draw_tface__set_draw);
1031
1032                 /* drawing game engine text hack */
1033                 if (!editing && prop && me->tface) {
1034                         DerivedMesh *ddm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
1035                         MFace *mface= me->mface;
1036                         MTFace *tface= me->mtface;
1037                         MCol *mcol= me->mcol;   /* why does mcol exist? */
1038                         int start= 0, totface= me->totface;
1039
1040                         tface+= start;
1041                         mcol+= start*4;
1042                         for (a=start; a<totface; a++, tface++, mcol+=4) {
1043                                 MFace *mf= &mface[a];
1044                                 int mode= tface->mode;
1045                                 int matnr= mf->mat_nr;
1046                                 int mf_smooth= mf->flag & ME_SMOOTH;
1047
1048                                 if (!(tface->flag&TF_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
1049                                         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);
1050                                         float v1[3], v2[3], v3[3], v4[3];
1051                                         char string[MAX_PROPSTRING];
1052                                         int characters, index;
1053                                         ImBuf *ibuf;
1054                                         float curpos;
1055
1056                                         if (badtex)
1057                                                 continue;
1058
1059                                         ddm->getVertCo(ddm, mf->v1, v1);
1060                                         ddm->getVertCo(ddm, mf->v2, v2);
1061                                         ddm->getVertCo(ddm, mf->v3, v3);
1062                                         if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4);
1063
1064                                         // The BM_FONT handling code is duplicated in the gameengine
1065                                         // Search for 'Frank van Beek' ;-)
1066                                         // string = "Frank van Beek";
1067
1068                                         set_property_valstr(prop, string);
1069                                         characters = strlen(string);
1070                                         
1071                                         ibuf= BKE_image_get_ibuf(tface->tpage, NULL);
1072                                         if (ibuf == NULL) {
1073                                                 characters = 0;
1074                                         }
1075
1076                                         if (!mf_smooth) {
1077                                                 float nor[3];
1078
1079                                                 CalcNormFloat(v1, v2, v3, nor);
1080
1081                                                 glNormal3fv(nor);
1082                                         }
1083
1084                                         curpos= 0.0;
1085                                         glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
1086                                         for (index = 0; index < characters; index++) {
1087                                                 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
1088                                                 int character = string[index];
1089                                                 char *cp= NULL;
1090
1091                                                 // lets calculate offset stuff
1092                                                 // space starts at offset 1
1093                                                 // character = character - ' ' + 1;
1094                                                 
1095                                                 matrixGlyph(ibuf, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
1096                                                 movex+= curpos;
1097
1098                                                 if (tface->mode & TF_OBCOL) glColor3ubv(obcol);
1099                                                 else if (mcol) cp= (char *)mcol;
1100                                                 else glColor3ub(255, 255, 255);
1101
1102                                                 glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
1103                                                 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
1104                                                 glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
1105                                                 
1106                                                 glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
1107                                                 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
1108                                                 glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
1109                         
1110                                                 glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
1111                                                 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
1112                                                 glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
1113                         
1114                                                 if(mf->v4) {
1115                                                         glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
1116                                                         if (cp) glColor3ub(cp[15], cp[14], cp[13]);
1117                                                         glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
1118                                                 }
1119
1120                                                 curpos+= advance;
1121                                         }
1122                                         glEnd();
1123                                 }
1124                         }
1125
1126                         ddm->release(ddm);
1127                 }
1128
1129                 /* switch off textures */
1130                 set_tpage(0);
1131         }
1132         glShadeModel(GL_FLAT);
1133         glDisable(GL_CULL_FACE);
1134         
1135         if(ob==OBACT && (G.f & G_FACESELECT) && me && me->mtface) {
1136                 draw_tfaces3D(ob, me, dm);
1137         }
1138         
1139                 /* XXX, bad patch - default_gl_light() calls
1140                  * glLightfv(GL_LIGHT_POSITION, ...) which
1141                  * is transformed by the current matrix... we
1142                  * need to make sure that matrix is identity.
1143                  * 
1144                  * It would be better if drawmesh.c kept track
1145                  * of and restored the light settings it changed.
1146                  *  - zr
1147                  */
1148         glPushMatrix();
1149         glLoadIdentity();       
1150         default_gl_light();
1151         glPopMatrix();
1152         
1153         glFrontFace(GL_CCW);
1154
1155         if(dt > OB_SOLID && !(ob==OBACT && (G.f & G_FACESELECT) && me && me->mtface)) {
1156                 if(ob->flag & SELECT) {
1157                         BIF_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
1158                 } else {
1159                         BIF_ThemeColor(TH_WIRE);
1160                 }
1161                 dm->drawLooseEdges(dm);
1162         }
1163
1164         dm->release(dm);
1165 }
1166
1167 void init_realtime_GL(void)
1168 {               
1169         glMatrixMode(GL_TEXTURE);
1170         glLoadIdentity();
1171         glMatrixMode(GL_MODELVIEW);
1172
1173 }
1174