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