Use GL_ALPHA_TEST when drawing alpha faces in the 3d view, as suggested
[plumiferos.git] / source / blender / src / drawmesh.c
blob820cde0ccb146a5c3f49e33b598ab1400d3277ce
1 /**
2 * $Id: drawmesh.c 12710 2007-11-28 21:42:27Z blendix $
4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
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.
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.
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.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
33 #include <string.h>
34 #include <math.h>
36 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_edgehash.h"
41 #include "BLI_editVert.h"
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
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"
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"
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"
76 #include "BDR_editface.h"
77 #include "BDR_vpaint.h"
78 #include "BDR_drawmesh.h"
80 #include "BSE_drawview.h"
82 #include "blendef.h"
83 #include "nla.h"
85 #ifndef GL_CLAMP_TO_EDGE
86 #define GL_CLAMP_TO_EDGE 0x812F
87 #endif
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)
97 #else
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 */
103 #endif
105 /* (n&(n-1)) zeros the least significant bit of n */
106 static int is_pow2(int num) {
107 return ((num)&(num-1))==0;
109 static int smaller_pow2(int num) {
110 while (!is_pow2(num))
111 num= num&(num-1);
112 return num;
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;
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);
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;
133 /* local prototypes --------------- */
134 void update_realtime_textures(void);
137 /* static int source, dest; also not used */
140 * Enables or disable mipmapping for realtime images.
141 * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
143 void set_mipmap(int mipmap)
145 if (fDoMipMap != (mipmap != 0)) {
146 free_all_realtime_images();
147 fDoMipMap = mipmap != 0;
152 * Returns the current setting for mipmapping.
154 static int get_mipmap(void)
156 return fDoMipMap && (!(G.f & G_TEXTUREPAINT));
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).
165 void set_linear_mipmap(int linear)
167 if (fLinearMipMap != (linear != 0)) {
168 free_all_realtime_images();
169 fLinearMipMap = linear != 0;
174 * Returns the current setting for linear mipmapping.
176 int get_linear_mipmap(void)
178 return fLinearMipMap;
183 * Resets the realtime image cache variables.
185 void clear_realtime_image_cache()
187 fCurpage = NULL;
188 fCurtile = 0;
189 fCurmode = 0;
190 fCurtileXRep = 0;
191 fCurtileYRep = 0;
194 /* REMEMBER! Changes here must go into my_set_tpage() as well */
195 int set_tpage(MTFace *tface)
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;
204 /* disable */
205 if(tface==0) {
206 if(lasttface==0) return 0;
208 lasttface= 0;
209 fCurtile= 0;
210 fCurpage= 0;
211 if(fCurmode!=0) {
212 glMatrixMode(GL_TEXTURE);
213 glLoadIdentity();
214 glMatrixMode(GL_MODELVIEW);
216 fCurmode= 0;
217 fCurtileXRep=0;
218 fCurtileYRep=0;
219 alphamode= -1;
221 glDisable(GL_BLEND);
222 glDisable(GL_TEXTURE_2D);
223 glDisable(GL_TEXTURE_GEN_S);
224 glDisable(GL_TEXTURE_GEN_T);
226 return 0;
228 lasttface= tface;
230 if( alphamode != tface->transp) {
231 alphamode= tface->transp;
233 if(alphamode) {
234 glEnable(GL_BLEND);
236 if(alphamode==TF_ADD) {
237 glBlendFunc(GL_ONE, GL_ONE);
238 /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
240 else if(alphamode==TF_ALPHA) {
241 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
243 /* added after 2.45 to clip alpha */
244 glEnable ( GL_ALPHA_TEST );
245 glAlphaFunc ( GL_GREATER, 0.001 );
248 /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
250 /* else { */
251 /* glBlendFunc(GL_ONE, GL_ONE); */
252 /* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
253 /* } */
254 } else {
255 glDisable(GL_BLEND);
256 glDisable ( GL_ALPHA_TEST );
260 ima= tface->tpage;
262 /* Enable or disable reflection mapping */
263 if (ima && (ima->flag & IMA_REFLECT)){
265 // glActiveTextureARB(GL_TEXTURE0_ARB);
266 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
267 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
269 glEnable(GL_TEXTURE_GEN_S);
270 glEnable(GL_TEXTURE_GEN_T);
272 /* Handle multitexturing here */
274 else{
275 glDisable(GL_TEXTURE_GEN_S);
276 glDisable(GL_TEXTURE_GEN_T);
279 tilemode= tface->mode & TF_TILES;
280 tileXRep = 0;
281 tileYRep = 0;
282 if (ima) {
283 tileXRep = ima->xrep;
284 tileYRep = ima->yrep;
288 if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurtileXRep==tileXRep && fCurtileYRep == tileYRep) return ima!=0;
290 if(tilemode!=fCurmode || fCurtileXRep!=tileXRep || fCurtileYRep != tileYRep) {
291 glMatrixMode(GL_TEXTURE);
292 glLoadIdentity();
294 if(tilemode && ima!=NULL)
295 glScalef(ima->xrep, ima->yrep, 1.0);
297 glMatrixMode(GL_MODELVIEW);
300 if(ima==NULL || ima->ok==0) {
301 glDisable(GL_TEXTURE_2D);
303 fCurtile= tface->tile;
304 fCurpage= 0;
305 fCurmode= tilemode;
306 fCurtileXRep = tileXRep;
307 fCurtileYRep = tileYRep;
309 return 0;
312 ibuf= BKE_image_get_ibuf(ima, NULL);
313 if(ibuf==NULL) {
315 fCurtile= tface->tile;
316 fCurpage= 0;
317 fCurmode= tilemode;
318 fCurtileXRep = tileXRep;
319 fCurtileYRep = tileYRep;
321 glDisable(GL_TEXTURE_2D);
322 return 0;
325 if ((ibuf->rect==NULL) && ibuf->rect_float)
326 IMB_rect_from_float(ibuf);
328 if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
329 else fCurtile= tface->tile;
331 if(tilemode) {
333 if(ima->repbind==0) make_repbind(ima);
335 if(fCurtile>=ima->totbind) fCurtile= 0;
337 /* this happens when you change repeat buttons */
338 if(ima->repbind) bind= ima->repbind+fCurtile;
339 else bind= &ima->bindcode;
341 if(*bind==0) {
343 fTexwindx= ibuf->x/ima->xrep;
344 fTexwindy= ibuf->y/ima->yrep;
346 if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1;
348 fTexwinsy= fCurtile / ima->xrep;
349 fTexwinsx= fCurtile - fTexwinsy*ima->xrep;
351 fTexwinsx*= fTexwindx;
352 fTexwinsy*= fTexwindy;
354 tpx= fTexwindx;
355 tpy= fTexwindy;
357 rect= ibuf->rect + fTexwinsy*ibuf->x + fTexwinsx;
360 else {
361 bind= &ima->bindcode;
363 if(*bind==0) {
364 tpx= ibuf->x;
365 tpy= ibuf->y;
366 rect= ibuf->rect;
370 if(*bind==0) {
371 int rectw= tpx, recth= tpy;
372 unsigned int *tilerect= NULL, *scalerect= NULL;
375 * Maarten:
376 * According to Ton this code is not needed anymore. It was used only
377 * in really old Blenders.
378 * Reevan:
379 * Actually it is needed for backwards compatibility. Simpledemo 6 does not display correctly without it.
381 #if 1
382 if (tilemode) {
383 int y;
385 tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
386 for (y=0; y<recth; y++) {
387 unsigned int *rectrow= &rect[y*ibuf->x];
388 unsigned int *tilerectrow= &tilerect[y*rectw];
390 memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
393 rect= tilerect;
395 #endif
396 if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
397 rectw= smaller_pow2_limit(rectw);
398 recth= smaller_pow2_limit(recth);
400 scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
401 gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
402 rect= scalerect;
405 glGenTextures(1, (GLuint *)bind);
407 if((G.f & G_DEBUG) || !*bind) {
408 GLenum error = glGetError();
409 printf("Texture: %s\n", ima->id.name+2);
410 printf("name: %d, tpx: %d\n", *bind, tpx);
411 printf("tile: %d, mode: %d\n", fCurtile, tilemode);
412 if (error)
413 printf("error: %s\n", gluErrorString(error));
415 glBindTexture( GL_TEXTURE_2D, *bind);
417 if (!get_mipmap())
419 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
420 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
421 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
422 } else
424 int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
426 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
430 ima->tpageflag |= IMA_MIPMAP_COMPLETE;
433 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
435 if (tilerect)
436 MEM_freeN(tilerect);
437 if (scalerect)
438 MEM_freeN(scalerect);
440 else glBindTexture( GL_TEXTURE_2D, *bind);
442 /* dont tile x/y as set the the game properties */
443 if (ima->tpageflag & IMA_CLAMP_U)
444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
445 else
446 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
447 if (ima->tpageflag & IMA_CLAMP_V)
448 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
449 else
450 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
452 /* tag_image_time(ima);*/ /* Did this get lost in the image recode? */
454 glEnable(GL_TEXTURE_2D);
456 fCurpage= ima;
457 fCurmode= tilemode;
458 fCurtileXRep = tileXRep;
459 fCurtileYRep = tileYRep;
461 return 1;
464 void update_realtime_image(Image *ima, int x, int y, int w, int h)
466 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
468 if (ima->repbind || get_mipmap() || !ima->bindcode || !ibuf ||
469 (!is_pow2(ibuf->x) || !is_pow2(ibuf->y)) ||
470 (w == 0) || (h == 0)) {
471 /* these special cases require full reload still */
472 free_realtime_image(ima);
474 else {
475 int row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
476 int skip_pixels = glaGetOneInteger(GL_UNPACK_SKIP_PIXELS);
477 int skip_rows = glaGetOneInteger(GL_UNPACK_SKIP_ROWS);
479 if ((ibuf->rect==NULL) && ibuf->rect_float)
480 IMB_rect_from_float(ibuf);
482 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
484 glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
485 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
486 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
488 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
489 GL_UNSIGNED_BYTE, ibuf->rect);
491 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
492 glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
493 glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
495 if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
496 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
500 void free_realtime_image(Image *ima)
502 if(ima->bindcode) {
503 glDeleteTextures(1, (GLuint *)&ima->bindcode);
504 ima->bindcode= 0;
505 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
507 if(ima->repbind) {
508 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
510 MEM_freeN(ima->repbind);
511 ima->repbind= NULL;
512 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
516 void free_all_realtime_images(void)
518 Image* ima;
520 for(ima=G.main->image.first; ima; ima=ima->id.next)
521 free_realtime_image(ima);
524 /* these two functions are called on entering and exiting texture paint mode,
525 temporary disabling/enabling mipmapping on all images for quick texture
526 updates with glTexSubImage2D. images that didn't change don't have to be
527 re-uploaded to OpenGL */
528 void texpaint_disable_mipmap(void)
530 Image* ima;
532 if(!fDoMipMap)
533 return;
535 for(ima=G.main->image.first; ima; ima=ima->id.next) {
536 if(ima->bindcode) {
537 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
539 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
544 void texpaint_enable_mipmap(void)
546 Image* ima;
548 if(!fDoMipMap)
549 return;
551 for(ima=G.main->image.first; ima; ima=ima->id.next) {
552 if(ima->bindcode) {
553 if(ima->tpageflag & IMA_MIPMAP_COMPLETE) {
554 int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
556 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
558 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
560 else
561 free_realtime_image(ima);
566 void make_repbind(Image *ima)
568 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
570 if(ibuf==NULL) return;
572 if(ima->repbind) {
573 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
574 MEM_freeN(ima->repbind);
575 ima->repbind= 0;
576 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
578 ima->totbind= ima->xrep*ima->yrep;
579 if(ima->totbind>1) {
580 ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
584 void update_realtime_textures()
586 Image *ima;
588 ima= G.main->image.first;
589 while(ima) {
590 if(ima->tpageflag & IMA_TWINANIM) {
591 if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
593 /* check: is bindcode not in the array? Free. (to do) */
595 ima->lastframe++;
596 if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
599 ima= ima->id.next;
603 /***/
605 /* Flags for marked edges */
606 enum {
607 eEdge_Visible = (1<<0),
608 eEdge_Select = (1<<1),
609 eEdge_Active = (1<<2),
610 eEdge_SelectAndActive = (1<<3),
611 eEdge_ActiveFirst = (1<<4),
612 eEdge_ActiveLast = (1<<5)
615 /* Creates a hash of edges to flags indicating
616 * adjacent tface select/active/etc flags.
618 static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
620 int *flags_p;
622 if (!BLI_edgehash_haskey(eh, v0, v1)) {
623 BLI_edgehash_insert(eh, v0, v1, 0);
626 flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
627 *flags_p |= flags;
630 EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
632 EdgeHash *eh = BLI_edgehash_new();
633 int i;
635 for (i=0; i<me->totface; i++) {
636 MFace *mf = &me->mface[i];
637 MTFace *tf = &me->mtface[i];
639 if (mf->v3) {
640 if (!(mf->flag&ME_HIDE)) {
641 unsigned int flags = eEdge_Visible;
642 if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select;
643 if (tf->flag&TF_ACTIVE) {
644 flags |= eEdge_Active;
645 if (mf->flag&ME_FACE_SEL) flags |= eEdge_SelectAndActive;
648 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
649 get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
650 if (mf->v4) {
651 get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
652 get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
653 } else {
654 get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
657 if (tf->flag&TF_ACTIVE) {
658 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, eEdge_ActiveFirst);
659 get_marked_edge_info__orFlags(eh, mf->v1, mf->v4?mf->v4:mf->v3, eEdge_ActiveLast);
665 return eh;
669 static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
671 struct { Mesh *me; EdgeHash *eh; } *data = userData;
672 MEdge *med = &data->me->medge[index];
673 unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
675 if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) {
676 return 0;
677 } else if(G.f & G_DRAWEDGES){
678 if (G.f&G_HIDDENEDGES) {
679 return 1;
680 } else {
681 return (flags & eEdge_Visible);
683 } else {
684 return (flags & eEdge_Select);
687 static int draw_tfaces3D__setSeamOpts(void *userData, int index)
689 struct { Mesh *me; EdgeHash *eh; } *data = userData;
690 MEdge *med = &data->me->medge[index];
691 unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
693 if (med->flag&ME_SEAM) {
694 if (G.f&G_HIDDENEDGES) {
695 return 1;
696 } else {
697 return (flags & eEdge_Visible);
699 } else {
700 return 0;
703 static int draw_tfaces3D__setSelectOpts(void *userData, int index)
705 struct { Mesh *me; EdgeHash *eh; } *data = userData;
706 MEdge *med = &data->me->medge[index];
707 unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
709 return flags & eEdge_Select;
711 static int draw_tfaces3D__setActiveOpts(void *userData, int index)
713 struct { Mesh *me; EdgeHash *eh; } *data = userData;
714 MEdge *med = &data->me->medge[index];
715 unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
717 if (flags & eEdge_Active) {
718 if (flags & eEdge_ActiveLast) {
719 glColor3ub(255, 0, 0);
720 } else if (flags & eEdge_ActiveFirst) {
721 glColor3ub(0, 255, 0);
722 } else if (flags & eEdge_SelectAndActive) {
723 glColor3ub(255, 255, 0);
724 } else {
725 glColor3ub(255, 0, 255);
728 return 1;
729 } else {
730 return 0;
733 static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
735 Mesh *me = (Mesh*)userData;
737 if (me->mtface) {
738 MFace *mface = &me->mface[index];
739 if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL))
740 return 2; /* Don't set color */
741 else
742 return 0;
743 } else
744 return 0;
746 static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
748 struct { Mesh *me; EdgeHash *eh; } data;
750 data.me = me;
751 data.eh = get_tface_mesh_marked_edge_info(me);
753 glEnable(GL_DEPTH_TEST);
754 glDisable(GL_LIGHTING);
755 bglPolygonOffset(1.0);
757 /* Draw (Hidden) Edges */
758 BIF_ThemeColor(TH_EDGE_FACESEL);
759 dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
761 /* Draw Seams */
762 if(G.f & G_DRAWSEAMS) {
763 BIF_ThemeColor(TH_EDGE_SEAM);
764 glLineWidth(2);
766 dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
768 glLineWidth(1);
771 /* Draw Selected Faces */
772 if(G.f & G_DRAWFACES) {
773 glEnable(GL_BLEND);
774 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
775 BIF_ThemeColor4(TH_FACE_SELECT);
777 dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
779 glDisable(GL_BLEND);
782 bglPolygonOffset(1.0);
784 /* Draw Stippled Outline for selected faces */
785 glColor3ub(255, 255, 255);
786 setlinestyle(1);
787 dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
788 setlinestyle(0);
790 dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
792 bglPolygonOffset(0.0); // resets correctly now, even after calling accumulated offsets
794 BLI_edgehash_free(data.eh, NULL);
797 static int set_gl_light(Object *ob)
799 Base *base;
800 Lamp *la;
801 int count;
802 /* float zero[4]= {0.0, 0.0, 0.0, 0.0}; */
803 float vec[4];
805 vec[3]= 1.0;
807 for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
809 count= 0;
811 base= FIRSTBASE;
812 while(base) {
813 if(base->object->type==OB_LAMP ) {
814 if(base->lay & G.vd->lay) {
815 if(base->lay & ob->lay)
817 la= base->object->data;
819 glPushMatrix();
820 glLoadMatrixf((float *)G.vd->viewmat);
822 where_is_object_simul(base->object);
823 VECCOPY(vec, base->object->obmat[3]);
825 if(la->type==LA_SUN) {
826 vec[0]= base->object->obmat[2][0];
827 vec[1]= base->object->obmat[2][1];
828 vec[2]= base->object->obmat[2][2];
829 vec[3]= 0.0;
830 glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
832 else {
833 vec[3]= 1.0;
834 glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
835 glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
836 glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
837 /* post 2.25 engine supports quad lights */
838 glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
840 if(la->type==LA_SPOT) {
841 vec[0]= -base->object->obmat[2][0];
842 vec[1]= -base->object->obmat[2][1];
843 vec[2]= -base->object->obmat[2][2];
844 glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
845 glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
846 glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
848 else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
851 vec[0]= la->energy*la->r;
852 vec[1]= la->energy*la->g;
853 vec[2]= la->energy*la->b;
854 vec[3]= 1.0;
855 glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec);
856 glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero);
857 glEnable(GL_LIGHT0+count);
859 glPopMatrix();
861 count++;
862 if(count>7) break;
866 base= base->next;
869 return count;
872 static Material *give_current_material_or_def(Object *ob, int matnr)
874 extern Material defmaterial; // render module abuse...
875 Material *ma= give_current_material(ob, matnr);
877 return ma?ma:&defmaterial;
880 static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
882 static int c_textured;
883 static int c_lit;
884 static int c_doublesided;
885 static MTFace *c_texface;
886 static Object *c_litob;
887 static int c_litmatnr;
888 static int c_badtex;
890 if (clearcache) {
891 c_textured= c_lit= c_doublesided= -1;
892 c_texface= (MTFace*) -1;
893 c_litob= (Object*) -1;
894 c_litmatnr= -1;
895 c_badtex= 0;
898 if (texface) {
899 lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
900 textured = textured && (texface->mode&TF_TEX);
901 doublesided = texface->mode&TF_TWOSIDE;
902 } else {
903 textured = 0;
906 if (doublesided!=c_doublesided) {
907 if (doublesided) glDisable(GL_CULL_FACE);
908 else glEnable(GL_CULL_FACE);
910 c_doublesided= doublesided;
913 if (textured!=c_textured || texface!=c_texface) {
914 if (textured ) {
915 c_badtex= !set_tpage(texface);
916 } else {
917 set_tpage(0);
918 c_badtex= 0;
920 c_textured= textured;
921 c_texface= texface;
924 if (c_badtex) lit= 0;
925 if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
926 if (lit) {
927 Material *ma= give_current_material_or_def(litob, litmatnr+1);
928 float spec[4];
930 spec[0]= ma->spec*ma->specr;
931 spec[1]= ma->spec*ma->specg;
932 spec[2]= ma->spec*ma->specb;
933 spec[3]= 1.0;
935 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
936 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
937 glEnable(GL_LIGHTING);
938 glEnable(GL_COLOR_MATERIAL);
940 else {
941 glDisable(GL_LIGHTING);
942 glDisable(GL_COLOR_MATERIAL);
944 c_lit= lit;
945 c_litob= litob;
946 c_litmatnr= litmatnr;
949 return c_badtex;
952 /* Icky globals, fix with userdata parameter */
954 struct TextureDrawState {
955 Object *ob;
956 int islit, istex;
957 unsigned char obcol[4];
958 } Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
960 static void draw_textured_begin(Object *ob)
962 unsigned char obcol[4];
963 int istex, solidtex= 0;
965 if(G.vd->drawtype==OB_SOLID || ob==G.obedit) {
966 /* draw with default lights in solid draw mode and edit mode */
967 solidtex= 1;
968 Gtexdraw.islit= -1;
970 else
971 /* draw with lights in the scene otherwise */
972 Gtexdraw.islit= set_gl_light(ob);
974 obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
975 obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
976 obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
977 obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
979 glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
980 if(solidtex || G.vd->drawtype==OB_TEXTURE) istex= 1;
981 else istex= 0;
983 Gtexdraw.ob = ob;
984 Gtexdraw.istex = istex;
985 memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
986 set_draw_settings_cached(1, 0, 0, Gtexdraw.islit, 0, 0, 0);
988 glShadeModel(GL_SMOOTH);
991 static void draw_textured_end()
993 /* switch off textures */
994 set_tpage(0);
996 glShadeModel(GL_FLAT);
997 glDisable(GL_CULL_FACE);
999 /* XXX, bad patch - default_gl_light() calls
1000 * glLightfv(GL_LIGHT_POSITION, ...) which
1001 * is transformed by the current matrix... we
1002 * need to make sure that matrix is identity.
1004 * It would be better if drawmesh.c kept track
1005 * of and restored the light settings it changed.
1006 * - zr
1008 glPushMatrix();
1009 glLoadIdentity();
1010 default_gl_light();
1011 glPopMatrix();
1015 static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
1017 if (tface && (tface->mode&TF_INVISIBLE)) return 0;
1019 if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) {
1020 glColor3ub(0xFF, 0x00, 0xFF);
1021 return 2; /* Don't set color */
1022 } else if (tface && tface->mode&TF_OBCOL) {
1023 glColor3ubv(Gtexdraw.obcol);
1024 return 2; /* Don't set color */
1025 } else if (!mcol) {
1026 if (tface) glColor3f(1.0, 1.0, 1.0);
1027 else {
1028 Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
1029 if(ma) glColor3f(ma->r, ma->g, ma->b);
1030 else glColor3f(1.0, 1.0, 1.0);
1032 return 2; /* Don't set color */
1033 } else {
1034 return 1; /* Set color from mcol */
1038 static int draw_tface_mapped__set_draw(void *userData, int index)
1040 Mesh *me = (Mesh*)userData;
1041 MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
1042 MFace *mface = (me->mface)? &me->mface[index]: NULL;
1043 MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
1044 int matnr = me->mface[index].mat_nr;
1045 if (mface && mface->flag&ME_HIDE) return 0;
1046 return draw_tface__set_draw(tface, mcol, matnr);
1049 static int draw_em_tf_mapped__set_draw(void *userData, int index)
1051 EditMesh *em = userData;
1052 EditFace *efa = EM_get_face_for_index(index);
1053 MTFace *tface;
1054 MCol *mcol;
1055 int matnr;
1057 if (efa==NULL || efa->h)
1058 return 0;
1060 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1061 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1062 matnr = efa->mat_nr;
1064 return draw_tface__set_draw(tface, mcol, matnr);
1067 static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
1069 Mesh *me = (Mesh*)userData;
1070 MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
1071 MFace *mface = (me->mface)? &me->mface[index]: NULL;
1073 if (tface) {
1074 if ((mface->flag&ME_HIDE) || (tface->mode&TF_INVISIBLE))
1075 return 0;
1077 *drawSmooth_r = 1;
1078 return 1;
1081 static void draw_game_text_mesh(Object *ob, Mesh *me)
1083 DerivedMesh *ddm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
1084 MFace *mface= me->mface;
1085 MTFace *tface= me->mtface;
1086 MCol *mcol= me->mcol; /* why does mcol exist? */
1087 bProperty *prop = get_property(ob, "Text");
1088 int a, start= 0, totface= me->totface;
1090 tface+= start;
1091 mcol+= start*4;
1092 for (a=start; a<totface; a++, tface++, mcol+=4) {
1093 MFace *mf= &mface[a];
1094 int mode= tface->mode;
1095 int matnr= mf->mat_nr;
1096 int mf_smooth= mf->flag & ME_SMOOTH;
1098 if (!(mf->flag&ME_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
1099 int badtex= set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE);
1100 float v1[3], v2[3], v3[3], v4[3];
1101 char string[MAX_PROPSTRING];
1102 int characters, index;
1103 ImBuf *ibuf;
1104 float curpos;
1106 if (badtex)
1107 continue;
1109 ddm->getVertCo(ddm, mf->v1, v1);
1110 ddm->getVertCo(ddm, mf->v2, v2);
1111 ddm->getVertCo(ddm, mf->v3, v3);
1112 if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4);
1114 // The BM_FONT handling code is duplicated in the gameengine
1115 // Search for 'Frank van Beek' ;-)
1116 // string = "Frank van Beek";
1118 set_property_valstr(prop, string);
1119 characters = strlen(string);
1121 ibuf= BKE_image_get_ibuf(tface->tpage, NULL);
1122 if (ibuf == NULL) {
1123 characters = 0;
1126 if (!mf_smooth) {
1127 float nor[3];
1129 CalcNormFloat(v1, v2, v3, nor);
1131 glNormal3fv(nor);
1134 curpos= 0.0;
1135 glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
1136 for (index = 0; index < characters; index++) {
1137 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
1138 int character = string[index];
1139 char *cp= NULL;
1141 // lets calculate offset stuff
1142 // space starts at offset 1
1143 // character = character - ' ' + 1;
1145 matrixGlyph(ibuf, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
1146 movex+= curpos;
1148 if (tface->mode & TF_OBCOL)
1149 glColor3ubv(Gtexdraw.obcol);
1150 else if (me->mcol) cp= (char *)mcol;
1151 else glColor3ub(255, 255, 255);
1153 glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
1154 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
1155 glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
1157 glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
1158 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
1159 glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
1161 glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
1162 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
1163 glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
1165 if(mf->v4) {
1166 glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
1167 if (cp) glColor3ub(cp[15], cp[14], cp[13]);
1168 glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
1171 curpos+= advance;
1173 glEnd();
1177 ddm->release(ddm);
1180 void draw_mesh_textured(Object *ob, DerivedMesh *dm, int faceselect)
1182 Mesh *me= ob->data;
1183 int editing= 0;
1185 /* correct for negative scale */
1186 if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
1187 else glFrontFace(GL_CCW);
1189 /* draw the textured mesh */
1190 draw_textured_begin(ob);
1192 #ifdef WITH_VERSE
1193 if(me->vnode) {
1194 /* verse-blender doesn't support uv mapping of textures yet */
1195 dm->drawFacesTex(dm, NULL);
1197 else {
1198 #endif
1199 if(ob==G.obedit)
1200 dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, G.editMesh);
1201 else if(faceselect) {
1202 if(G.f & G_WEIGHTPAINT)
1203 dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1);
1204 else
1205 dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
1207 else
1208 dm->drawFacesTex(dm, draw_tface__set_draw);
1209 #ifdef WITH_VERSE
1211 #endif
1213 /* draw game engine text hack - but not if we are editing the mesh */
1214 if (get_property(ob, "Text") && me->mtface) {
1215 if(ob==G.obedit)
1216 editing= 1;
1217 else if(ob==OBACT)
1218 if(G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT))
1219 editing= 1;
1221 if(!editing)
1222 draw_game_text_mesh(ob, me);
1225 draw_textured_end();
1227 /* draw edges and selected faces over textured mesh */
1228 if(!G.obedit && faceselect)
1229 draw_tfaces3D(ob, me, dm);
1231 /* reset from negative scale correction */
1232 glFrontFace(GL_CCW);
1234 /* in editmode, the blend mode needs to be set incase it was ADD */
1235 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1238 void init_realtime_GL(void)
1240 glMatrixMode(GL_TEXTURE);
1241 glLoadIdentity();
1242 glMatrixMode(GL_MODELVIEW);