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
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 *****
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"
64 #include "BKE_material.h"
66 #include "BKE_object.h"
67 #include "BKE_property.h"
68 #include "BKE_utildefines.h"
70 #include "BIF_editmesh.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"
85 #ifndef GL_CLAMP_TO_EDGE
86 #define GL_CLAMP_TO_EDGE 0x812F
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)
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 */
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
))
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
)
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()
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;
201 unsigned int *rect
=NULL
, *bind
;
202 int tpx
=0, tpy
=0, tilemode
, tileXRep
,tileYRep
;
206 if(lasttface
==0) return 0;
212 glMatrixMode(GL_TEXTURE
);
214 glMatrixMode(GL_MODELVIEW
);
222 glDisable(GL_TEXTURE_2D
);
223 glDisable(GL_TEXTURE_GEN_S
);
224 glDisable(GL_TEXTURE_GEN_T
);
230 if( alphamode
!= tface
->transp
) {
231 alphamode
= tface
->transp
;
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); */
251 /* glBlendFunc(GL_ONE, GL_ONE); */
252 /* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
256 glDisable ( GL_ALPHA_TEST
);
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 */
275 glDisable(GL_TEXTURE_GEN_S
);
276 glDisable(GL_TEXTURE_GEN_T
);
279 tilemode
= tface
->mode
& TF_TILES
;
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
);
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
;
306 fCurtileXRep
= tileXRep
;
307 fCurtileYRep
= tileYRep
;
312 ibuf
= BKE_image_get_ibuf(ima
, NULL
);
315 fCurtile
= tface
->tile
;
318 fCurtileXRep
= tileXRep
;
319 fCurtileYRep
= tileYRep
;
321 glDisable(GL_TEXTURE_2D
);
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
;
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
;
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
;
357 rect
= ibuf
->rect
+ fTexwinsy
*ibuf
->x
+ fTexwinsx
;
361 bind
= &ima
->bindcode
;
371 int rectw
= tpx
, recth
= tpy
;
372 unsigned int *tilerect
= NULL
, *scalerect
= NULL
;
376 * According to Ton this code is not needed anymore. It was used only
377 * in really old Blenders.
379 * Actually it is needed for backwards compatibility. Simpledemo 6 does not display correctly without it.
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
));
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
);
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
);
413 printf("error: %s\n", gluErrorString(error
));
415 glBindTexture( GL_TEXTURE_2D
, *bind
);
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
);
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
);
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
);
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
);
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
);
458 fCurtileXRep
= tileXRep
;
459 fCurtileYRep
= tileYRep
;
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
);
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
)
503 glDeleteTextures(1, (GLuint
*)&ima
->bindcode
);
505 ima
->tpageflag
&= ~IMA_MIPMAP_COMPLETE
;
508 glDeleteTextures(ima
->totbind
, (GLuint
*)ima
->repbind
);
510 MEM_freeN(ima
->repbind
);
512 ima
->tpageflag
&= ~IMA_MIPMAP_COMPLETE
;
516 void free_all_realtime_images(void)
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)
535 for(ima
=G
.main
->image
.first
; ima
; ima
=ima
->id
.next
) {
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)
551 for(ima
=G
.main
->image
.first
; ima
; ima
=ima
->id
.next
) {
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
);
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;
573 glDeleteTextures(ima
->totbind
, (GLuint
*)ima
->repbind
);
574 MEM_freeN(ima
->repbind
);
576 ima
->tpageflag
&= ~IMA_MIPMAP_COMPLETE
;
578 ima
->totbind
= ima
->xrep
*ima
->yrep
;
580 ima
->repbind
= MEM_callocN(sizeof(int)*ima
->totbind
, "repbind");
584 void update_realtime_textures()
588 ima
= G
.main
->image
.first
;
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) */
596 if(ima
->lastframe
> ima
->twend
) ima
->lastframe
= ima
->twsta
;
605 /* Flags for marked edges */
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
)
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
);
630 EdgeHash
*get_tface_mesh_marked_edge_info(Mesh
*me
)
632 EdgeHash
*eh
= BLI_edgehash_new();
635 for (i
=0; i
<me
->totface
; i
++) {
636 MFace
*mf
= &me
->mface
[i
];
637 MTFace
*tf
= &me
->mtface
[i
];
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
);
651 get_marked_edge_info__orFlags(eh
, mf
->v3
, mf
->v4
, flags
);
652 get_marked_edge_info__orFlags(eh
, mf
->v4
, mf
->v1
, flags
);
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
);
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
)) {
677 } else if(G
.f
& G_DRAWEDGES
){
678 if (G
.f
&G_HIDDENEDGES
) {
681 return (flags
& eEdge_Visible
);
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
) {
697 return (flags
& eEdge_Visible
);
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);
725 glColor3ub(255, 0, 255);
733 static int draw_tfaces3D__drawFaceOpts(void *userData
, int index
)
735 Mesh
*me
= (Mesh
*)userData
;
738 MFace
*mface
= &me
->mface
[index
];
739 if (!(mface
->flag
&ME_HIDE
) && (mface
->flag
&ME_FACE_SEL
))
740 return 2; /* Don't set color */
746 static void draw_tfaces3D(Object
*ob
, Mesh
*me
, DerivedMesh
*dm
)
748 struct { Mesh
*me
; EdgeHash
*eh
; } data
;
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
);
762 if(G
.f
& G_DRAWSEAMS
) {
763 BIF_ThemeColor(TH_EDGE_SEAM
);
766 dm
->drawMappedEdges(dm
, draw_tfaces3D__setSeamOpts
, &data
);
771 /* Draw Selected Faces */
772 if(G
.f
& G_DRAWFACES
) {
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
);
782 bglPolygonOffset(1.0);
784 /* Draw Stippled Outline for selected faces */
785 glColor3ub(255, 255, 255);
787 dm
->drawMappedEdges(dm
, draw_tfaces3D__setSelectOpts
, &data
);
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
)
802 /* float zero[4]= {0.0, 0.0, 0.0, 0.0}; */
807 for(count
=0; count
<8; count
++) glDisable(GL_LIGHT0
+count
);
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
;
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];
830 glLightfv(GL_LIGHT0
+count
, GL_POSITION
, vec
);
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
;
855 glLightfv(GL_LIGHT0
+count
, GL_DIFFUSE
, vec
);
856 glLightfv(GL_LIGHT0
+count
, GL_SPECULAR
, vec
);//zero);
857 glEnable(GL_LIGHT0
+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
;
884 static int c_doublesided
;
885 static MTFace
*c_texface
;
886 static Object
*c_litob
;
887 static int c_litmatnr
;
891 c_textured
= c_lit
= c_doublesided
= -1;
892 c_texface
= (MTFace
*) -1;
893 c_litob
= (Object
*) -1;
899 lit
= lit
&& (lit
==-1 || texface
->mode
&TF_LIGHT
);
900 textured
= textured
&& (texface
->mode
&TF_TEX
);
901 doublesided
= texface
->mode
&TF_TWOSIDE
;
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
) {
915 c_badtex
= !set_tpage(texface
);
920 c_textured
= textured
;
924 if (c_badtex
) lit
= 0;
925 if (lit
!=c_lit
|| litob
!=c_litob
|| litmatnr
!=c_litmatnr
) {
927 Material
*ma
= give_current_material_or_def(litob
, litmatnr
+1);
930 spec
[0]= ma
->spec
*ma
->specr
;
931 spec
[1]= ma
->spec
*ma
->specg
;
932 spec
[2]= ma
->spec
*ma
->specb
;
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
);
941 glDisable(GL_LIGHTING
);
942 glDisable(GL_COLOR_MATERIAL
);
946 c_litmatnr
= litmatnr
;
952 /* Icky globals, fix with userdata parameter */
954 struct TextureDrawState
{
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 */
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;
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 */
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.
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 */
1026 if (tface
) glColor3f(1.0, 1.0, 1.0);
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 */
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
);
1057 if (efa
==NULL
|| efa
->h
)
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
;
1074 if ((mface
->flag
&ME_HIDE
) || (tface
->mode
&TF_INVISIBLE
))
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
;
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
;
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
);
1129 CalcNormFloat(v1
, v2
, v3
, nor
);
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
];
1141 // lets calculate offset stuff
1142 // space starts at offset 1
1143 // character = character - ' ' + 1;
1145 matrixGlyph(ibuf
, character
, & centerx
, ¢ery
, &sizex
, &sizey
, &transx
, &transy
, &movex
, &movey
, &advance
);
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]);
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]);
1180 void draw_mesh_textured(Object
*ob
, DerivedMesh
*dm
, int faceselect
)
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
);
1194 /* verse-blender doesn't support uv mapping of textures yet */
1195 dm
->drawFacesTex(dm
, NULL
);
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);
1205 dm
->drawMappedFacesTex(dm
, draw_tface_mapped__set_draw
, me
);
1208 dm
->drawFacesTex(dm
, draw_tface__set_draw
);
1213 /* draw game engine text hack - but not if we are editing the mesh */
1214 if (get_property(ob
, "Text") && me
->mtface
) {
1218 if(G
.f
& (G_VERTEXPAINT
+G_FACESELECT
+G_TEXTUREPAINT
+G_WEIGHTPAINT
))
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
);
1242 glMatrixMode(GL_MODELVIEW
);