svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22935:23022
[blender.git] / source / blender / editors / space_view3d / 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  * Contributor(s): Blender Foundation, full update, glsl support
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <string.h>
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_arithb.h"
35 #include "BLI_edgehash.h"
36 #include "BLI_editVert.h"
37
38 #include "IMB_imbuf.h"
39 #include "IMB_imbuf_types.h"
40
41 #include "DNA_image_types.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_property_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_screen_types.h"
50 #include "DNA_view3d_types.h"
51 #include "DNA_userdef_types.h"
52
53 #include "BKE_bmfont.h"
54 #include "BKE_displist.h"
55 #include "BKE_DerivedMesh.h"
56 #include "BKE_effect.h"
57 #include "BKE_global.h"
58 #include "BKE_image.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_mesh.h"
62 #include "BKE_object.h"
63 #include "BKE_paint.h"
64 #include "BKE_property.h"
65 #include "BKE_utildefines.h"
66
67 #include "BIF_gl.h"
68 #include "BIF_glutil.h"
69
70 #include "UI_resources.h"
71 #include "UI_interface_icons.h"
72
73 #include "GPU_extensions.h"
74 #include "GPU_draw.h"
75
76 #include "ED_mesh.h"
77
78 #include "view3d_intern.h"      // own include
79
80 /***/
81
82         /* Flags for marked edges */
83 enum {
84         eEdge_Visible = (1<<0),
85         eEdge_Select = (1<<1),
86 };
87
88         /* Creates a hash of edges to flags indicating
89          * adjacent tface select/active/etc flags.
90          */
91 static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
92 {
93         int *flags_p;
94
95         if (!BLI_edgehash_haskey(eh, v0, v1)) {
96                 BLI_edgehash_insert(eh, v0, v1, 0);
97         }
98
99         flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
100         *flags_p |= flags;
101 }
102
103 static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
104 {
105         EdgeHash *eh = BLI_edgehash_new();
106         int i;
107         MFace *mf;
108         MTFace *tf = NULL;
109         
110         for (i=0; i<me->totface; i++) {
111                 mf = &me->mface[i];
112                 if (me->mtface)
113                         tf = &me->mtface[i];
114                 
115                 if (mf->v3) {
116                         if (!(mf->flag&ME_HIDE)) {
117                                 unsigned int flags = eEdge_Visible;
118                                 if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select;
119
120                                 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
121                                 get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
122                                 if (mf->v4) {
123                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
124                                         get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
125                                 } else {
126                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
127                                 }
128                         }
129                 }
130         }
131
132         return eh;
133 }
134
135
136 static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
137 {
138         struct { Mesh *me; EdgeHash *eh; } *data = userData;
139         Mesh *me= data->me;
140         MEdge *med = &me->medge[index];
141         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
142
143         if((me->drawflag & ME_DRAWSEAMS) && (med->flag&ME_SEAM)) {
144                 return 0;
145         } else if(me->drawflag & ME_DRAWEDGES){ 
146                 if (me->drawflag & ME_HIDDENEDGES) {
147                         return 1;
148                 } else {
149                         return (flags & eEdge_Visible);
150                 }
151         } else {
152                 return (flags & eEdge_Select);
153         }
154 }
155
156 static int draw_tfaces3D__setSeamOpts(void *userData, int index)
157 {
158         struct { Mesh *me; EdgeHash *eh; } *data = userData;
159         Mesh *me= data->me;
160         MEdge *med = &data->me->medge[index];
161         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
162
163         if (med->flag & ME_SEAM) {
164                 if (me->drawflag & ME_HIDDENEDGES) {
165                         return 1;
166                 } else {
167                         return (flags & eEdge_Visible);
168                 }
169         } else {
170                 return 0;
171         }
172 }
173
174 static int draw_tfaces3D__setSelectOpts(void *userData, int index)
175 {
176         struct { Mesh *me; EdgeHash *eh; } *data = userData;
177         MEdge *med = &data->me->medge[index];
178         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
179
180         return flags & eEdge_Select;
181 }
182
183 static int draw_tfaces3D__setActiveOpts(void *userData, int index)
184 {
185         struct { Mesh *me; EdgeHash *eh; } *data = userData;
186         MEdge *med = &data->me->medge[index];
187         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
188
189         if (flags & eEdge_Select) {
190                 return 1;
191         } else {
192                 return 0;
193         }
194 }
195
196 static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
197 {
198         Mesh *me = (Mesh*)userData;
199
200         MFace *mface = &me->mface[index];
201         if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL))
202                 return 2; /* Don't set color */
203         else
204                 return 0;
205 }
206
207 static void draw_tfaces3D(RegionView3D *rv3d, Object *ob, Mesh *me, DerivedMesh *dm)
208 {
209         struct { Mesh *me; EdgeHash *eh; } data;
210
211         data.me = me;
212         data.eh = get_tface_mesh_marked_edge_info(me);
213
214         glEnable(GL_DEPTH_TEST);
215         glDisable(GL_LIGHTING);
216         bglPolygonOffset(rv3d->dist, 1.0);
217
218                 /* Draw (Hidden) Edges */
219         UI_ThemeColor(TH_EDGE_FACESEL);
220         dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
221
222                 /* Draw Seams */
223         if(me->drawflag & ME_DRAWSEAMS) {
224                 UI_ThemeColor(TH_EDGE_SEAM);
225                 glLineWidth(2);
226
227                 dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
228
229                 glLineWidth(1);
230         }
231
232         /* Draw Selected Faces */
233         if(me->drawflag & ME_DRAWFACES) {
234                 glEnable(GL_BLEND);
235                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
236                 UI_ThemeColor4(TH_FACE_SELECT);
237
238                 dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
239
240                 glDisable(GL_BLEND);
241         }
242         
243         bglPolygonOffset(rv3d->dist, 1.0);
244
245                 /* Draw Stippled Outline for selected faces */
246         glColor3ub(255, 255, 255);
247         setlinestyle(1);
248         dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
249         setlinestyle(0);
250
251         dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
252
253         bglPolygonOffset(rv3d->dist, 0.0);      // resets correctly now, even after calling accumulated offsets
254
255         BLI_edgehash_free(data.eh, NULL);
256 }
257
258 static Material *give_current_material_or_def(Object *ob, int matnr)
259 {
260         extern Material defmaterial;    // render module abuse...
261         Material *ma= give_current_material(ob, matnr);
262
263         return ma?ma:&defmaterial;
264 }
265
266 static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
267 {
268         static int c_textured;
269         static int c_lit;
270         static int c_doublesided;
271         static MTFace *c_texface;
272         static Object *c_litob;
273         static int c_litmatnr;
274         static int c_badtex;
275
276         if (clearcache) {
277                 c_textured= c_lit= c_doublesided= -1;
278                 c_texface= (MTFace*) -1;
279                 c_litob= (Object*) -1;
280                 c_litmatnr= -1;
281                 c_badtex= 0;
282         }
283
284         if (texface) {
285                 lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
286                 textured = textured && (texface->mode&TF_TEX);
287                 doublesided = texface->mode&TF_TWOSIDE;
288         } else {
289                 textured = 0;
290         }
291
292         if (doublesided!=c_doublesided) {
293                 if (doublesided) glDisable(GL_CULL_FACE);
294                 else glEnable(GL_CULL_FACE);
295
296                 c_doublesided= doublesided;
297         }
298
299         if (textured!=c_textured || texface!=c_texface) {
300                 if (textured ) {
301                         c_badtex= !GPU_set_tpage(texface, !(litob->mode & OB_MODE_TEXTURE_PAINT));
302                 } else {
303                         GPU_set_tpage(NULL, 0);
304                         c_badtex= 0;
305                 }
306                 c_textured= textured;
307                 c_texface= texface;
308         }
309
310         if (c_badtex) lit= 0;
311         if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
312                 if (lit) {
313                         Material *ma= give_current_material_or_def(litob, litmatnr+1);
314                         float spec[4];
315
316                         spec[0]= ma->spec*ma->specr;
317                         spec[1]= ma->spec*ma->specg;
318                         spec[2]= ma->spec*ma->specb;
319                         spec[3]= 1.0;
320
321                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
322                         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
323                         glEnable(GL_LIGHTING);
324                         glEnable(GL_COLOR_MATERIAL);
325                 }
326                 else {
327                         glDisable(GL_LIGHTING); 
328                         glDisable(GL_COLOR_MATERIAL);
329                 }
330                 c_lit= lit;
331                 c_litob= litob;
332                 c_litmatnr= litmatnr;
333         }
334
335         return c_badtex;
336 }
337
338 /* Icky globals, fix with userdata parameter */
339
340 struct TextureDrawState {
341         Object *ob;
342         int islit, istex;
343         unsigned char obcol[4];
344 } Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
345
346 static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
347 {
348         unsigned char obcol[4];
349         int istex, solidtex= 0;
350
351         // XXX scene->obedit warning
352         if(v3d->drawtype==OB_SOLID || (ob==scene->obedit && v3d->drawtype!=OB_TEXTURE)) {
353                 /* draw with default lights in solid draw mode and edit mode */
354                 solidtex= 1;
355                 Gtexdraw.islit= -1;
356         }
357         else {
358                 /* draw with lights in the scene otherwise */
359                 Gtexdraw.islit= GPU_scene_object_lights(scene, ob, v3d->lay, rv3d->viewmat, get_view3d_ortho(v3d, rv3d));
360         }
361         
362         obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
363         obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
364         obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
365         obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
366         
367         glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
368         if(solidtex || v3d->drawtype==OB_TEXTURE) istex= 1;
369         else istex= 0;
370
371         Gtexdraw.ob = ob;
372         Gtexdraw.istex = istex;
373         memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
374         set_draw_settings_cached(1, 0, 0, Gtexdraw.islit, 0, 0, 0);
375         glShadeModel(GL_SMOOTH);
376 }
377
378 static void draw_textured_end()
379 {
380         /* switch off textures */
381         GPU_set_tpage(NULL, 0);
382
383         glShadeModel(GL_FLAT);
384         glDisable(GL_CULL_FACE);
385
386         /* XXX, bad patch - GPU_default_lights() calls
387          * glLightfv(GL_LIGHT_POSITION, ...) which
388          * is transformed by the current matrix... we
389          * need to make sure that matrix is identity.
390          * 
391          * It would be better if drawmesh.c kept track
392          * of and restored the light settings it changed.
393          *  - zr
394          */
395         glPushMatrix();
396         glLoadIdentity();       
397         GPU_default_lights();
398         glPopMatrix();
399 }
400
401
402 static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
403 {
404         if (tface && (tface->mode&TF_INVISIBLE)) return 0;
405
406         if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) {
407                 glColor3ub(0xFF, 0x00, 0xFF);
408                 return 2; /* Don't set color */
409         } else if (tface && tface->mode&TF_OBCOL) {
410                 glColor3ubv(Gtexdraw.obcol);
411                 return 2; /* Don't set color */
412         } else if (!mcol) {
413                 if (tface) glColor3f(1.0, 1.0, 1.0);
414                 else {
415                         Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
416                         if(ma) glColor3f(ma->r, ma->g, ma->b);
417                         else glColor3f(1.0, 1.0, 1.0);
418                 }
419                 return 2; /* Don't set color */
420         } else {
421                 return 1; /* Set color from mcol */
422         }
423 }
424
425 static int draw_tface_mapped__set_draw(void *userData, int index)
426 {
427         Mesh *me = (Mesh*)userData;
428         MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
429         MFace *mface = (me->mface)? &me->mface[index]: NULL;
430         MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
431         int matnr = me->mface[index].mat_nr;
432         if (mface && mface->flag&ME_HIDE) return 0;
433         return draw_tface__set_draw(tface, mcol, matnr);
434 }
435
436 static int draw_em_tf_mapped__set_draw(void *userData, int index)
437 {
438         EditMesh *em = userData;
439         EditFace *efa= EM_get_face_for_index(index);
440         MTFace *tface;
441         MCol *mcol;
442         int matnr;
443
444         if (efa==NULL || efa->h)
445                 return 0;
446
447         tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
448         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
449         matnr = efa->mat_nr;
450
451         return draw_tface__set_draw(tface, mcol, matnr);
452 }
453
454 static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
455 {
456         Mesh *me = (Mesh*)userData;
457         MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
458         MFace *mface = (me->mface)? &me->mface[index]: NULL;
459         
460         if ((mface->flag&ME_HIDE) || (tface && (tface->mode&TF_INVISIBLE))) 
461                         return 0;
462         
463         *drawSmooth_r = 1;
464         return 1;
465 }
466
467 void draw_mesh_text(Scene *scene, Object *ob, int glsl)
468 {
469         Mesh *me = ob->data;
470         DerivedMesh *ddm;
471         MFace *mf, *mface= me->mface;
472         MTFace *tface= me->mtface;
473         MCol *mcol= me->mcol;   /* why does mcol exist? */
474         bProperty *prop = get_ob_property(ob, "Text");
475         GPUVertexAttribs gattribs;
476         int a, totface= me->totface;
477
478         /* don't draw without tfaces */
479         if(!tface)
480                 return;
481
482         /* don't draw when editing */
483         if(ob == scene->obedit)
484                 return;
485         else if(ob==OBACT)
486                 if(paint_facesel_test(ob))
487                         return;
488
489         ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
490
491         for(a=0, mf=mface; a<totface; a++, tface++, mf++) {
492                 int mode= tface->mode;
493                 int matnr= mf->mat_nr;
494                 int mf_smooth= mf->flag & ME_SMOOTH;
495
496                 if (!(mf->flag&ME_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
497                         float v1[3], v2[3], v3[3], v4[3];
498                         char string[MAX_PROPSTRING];
499                         int characters, i, glattrib= -1, badtex= 0;
500
501                         if(glsl) {
502                                 GPU_enable_material(matnr+1, &gattribs);
503
504                                 for(i=0; i<gattribs.totlayer; i++) {
505                                         if(gattribs.layer[i].type == CD_MTFACE) {
506                                                 glattrib = gattribs.layer[i].glindex;
507                                                 break;
508                                         }
509                                 }
510                         }
511                         else {
512                                 badtex = set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE);
513                                 if (badtex) {
514                                         if (mcol) mcol+=4;
515                                         continue;
516                                 }
517                         }
518
519                         ddm->getVertCo(ddm, mf->v1, v1);
520                         ddm->getVertCo(ddm, mf->v2, v2);
521                         ddm->getVertCo(ddm, mf->v3, v3);
522                         if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4);
523
524                         // The BM_FONT handling is in the gpu module, shared with the
525                         // game engine, was duplicated previously
526
527                         set_property_valstr(prop, string);
528                         characters = strlen(string);
529                         
530                         if(!BKE_image_get_ibuf(tface->tpage, NULL))
531                                 characters = 0;
532
533                         if (!mf_smooth) {
534                                 float nor[3];
535
536                                 CalcNormFloat(v1, v2, v3, nor);
537
538                                 glNormal3fv(nor);
539                         }
540
541                         GPU_render_text(tface, tface->mode, string, characters,
542                                 (unsigned int*)mcol, v1, v2, v3, (mf->v4? v4: NULL), glattrib);
543                 }
544                 if (mcol) {
545                         mcol+=4;
546                 }
547         }
548
549         ddm->release(ddm);
550 }
551
552 void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
553 {
554         Mesh *me= ob->data;
555         
556         /* correct for negative scale */
557         if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
558         else glFrontFace(GL_CCW);
559         
560         /* draw the textured mesh */
561         draw_textured_begin(scene, v3d, rv3d, ob);
562
563         if(ob == scene->obedit) {
564                 dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
565         } else if(faceselect) {
566                 if(ob->mode & OB_MODE_WEIGHT_PAINT)
567                         dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1);
568                 else
569                         dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
570         }
571         else {
572                 dm->drawFacesTex(dm, draw_tface__set_draw);
573         }
574
575         /* draw game engine text hack */
576         if(get_ob_property(ob, "Text")) 
577                 draw_mesh_text(scene, ob, 0);
578
579         draw_textured_end();
580         
581         /* draw edges and selected faces over textured mesh */
582         if(!(ob == scene->obedit) && faceselect)
583                 draw_tfaces3D(rv3d, ob, me, dm);
584
585         /* reset from negative scale correction */
586         glFrontFace(GL_CCW);
587         
588         /* in editmode, the blend mode needs to be set incase it was ADD */
589         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
590 }
591