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