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