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