8f22c704fd023198782ec8d768e20d767d621b5b
[blender.git] / source / blender / src / 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  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <string.h>
31 #include <math.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36 #include "BLI_arithb.h"
37 #include "BLI_edgehash.h"
38 #include "BLI_editVert.h"
39
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42
43 #include "DNA_image_types.h"
44 #include "DNA_lamp_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_mesh_types.h"
47 #include "DNA_meshdata_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_property_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_view3d_types.h"
52 #include "DNA_userdef_types.h"
53
54 #include "BKE_bmfont.h"
55 #include "BKE_displist.h"
56 #include "BKE_DerivedMesh.h"
57 #include "BKE_effect.h"
58 #include "BKE_global.h"
59 #include "BKE_image.h"
60 #include "BKE_main.h"
61 #include "BKE_material.h"
62 #include "BKE_mesh.h"
63 #include "BKE_object.h"
64 #include "BKE_property.h"
65 #include "BKE_utildefines.h"
66
67 #include "BIF_editmesh.h"
68 #include "BIF_gl.h"
69 #include "BIF_glutil.h"
70 #include "BIF_mywindow.h"
71 #include "BIF_resources.h"
72
73 #include "BDR_editface.h"
74 #include "BDR_vpaint.h"
75 #include "BDR_drawmesh.h"
76
77 #include "BSE_drawview.h"
78
79 #include "GPU_extensions.h"
80 #include "GPU_draw.h"
81
82 #include "blendef.h"
83 #include "nla.h"
84
85 /***/
86
87         /* Flags for marked edges */
88 enum {
89         eEdge_Visible = (1<<0),
90         eEdge_Select = (1<<1),
91 };
92
93         /* Creates a hash of edges to flags indicating
94          * adjacent tface select/active/etc flags.
95          */
96 static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
97 {
98         int *flags_p;
99
100         if (!BLI_edgehash_haskey(eh, v0, v1)) {
101                 BLI_edgehash_insert(eh, v0, v1, 0);
102         }
103
104         flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
105         *flags_p |= flags;
106 }
107
108 static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
109 {
110         EdgeHash *eh = BLI_edgehash_new();
111         int i;
112         MFace *mf;
113         MTFace *tf = NULL;
114         
115         for (i=0; i<me->totface; i++) {
116                 mf = &me->mface[i];
117                 if (me->mtface)
118                         tf = &me->mtface[i];
119                 
120                 if (mf->v3) {
121                         if (!(mf->flag&ME_HIDE)) {
122                                 unsigned int flags = eEdge_Visible;
123                                 if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select;
124
125                                 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
126                                 get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
127                                 if (mf->v4) {
128                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
129                                         get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
130                                 } else {
131                                         get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
132                                 }
133                         }
134                 }
135         }
136
137         return eh;
138 }
139
140
141 static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
142 {
143         struct { Mesh *me; EdgeHash *eh; } *data = userData;
144         MEdge *med = &data->me->medge[index];
145         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
146
147         if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) {
148                 return 0;
149         } else if(G.f & G_DRAWEDGES){ 
150                 if (G.f&G_HIDDENEDGES) {
151                         return 1;
152                 } else {
153                         return (flags & eEdge_Visible);
154                 }
155         } else {
156                 return (flags & eEdge_Select);
157         }
158 }
159 static int draw_tfaces3D__setSeamOpts(void *userData, int index)
160 {
161         struct { Mesh *me; EdgeHash *eh; } *data = userData;
162         MEdge *med = &data->me->medge[index];
163         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
164
165         if (med->flag&ME_SEAM) {
166                 if (G.f&G_HIDDENEDGES) {
167                         return 1;
168                 } else {
169                         return (flags & eEdge_Visible);
170                 }
171         } else {
172                 return 0;
173         }
174 }
175 static int draw_tfaces3D__setSelectOpts(void *userData, int index)
176 {
177         struct { Mesh *me; EdgeHash *eh; } *data = userData;
178         MEdge *med = &data->me->medge[index];
179         uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
180
181         return flags & eEdge_Select;
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 static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
196 {
197         Mesh *me = (Mesh*)userData;
198
199         MFace *mface = &me->mface[index];
200         if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL))
201                 return 2; /* Don't set color */
202         else
203                 return 0;
204 }
205 static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
206 {
207         struct { Mesh *me; EdgeHash *eh; } data;
208
209         data.me = me;
210         data.eh = get_tface_mesh_marked_edge_info(me);
211
212         glEnable(GL_DEPTH_TEST);
213         glDisable(GL_LIGHTING);
214         bglPolygonOffset(1.0);
215
216                 /* Draw (Hidden) Edges */
217         BIF_ThemeColor(TH_EDGE_FACESEL);
218         dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
219
220                 /* Draw Seams */
221         if(G.f & G_DRAWSEAMS) {
222                 BIF_ThemeColor(TH_EDGE_SEAM);
223                 glLineWidth(2);
224
225                 dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
226
227                 glLineWidth(1);
228         }
229
230         /* Draw Selected Faces */
231         if(G.f & G_DRAWFACES) {
232                 glEnable(GL_BLEND);
233                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
234                 BIF_ThemeColor4(TH_FACE_SELECT);
235
236                 dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
237
238                 glDisable(GL_BLEND);
239         }
240         
241         bglPolygonOffset(1.0);
242
243                 /* Draw Stippled Outline for selected faces */
244         glColor3ub(255, 255, 255);
245         setlinestyle(1);
246         dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
247         setlinestyle(0);
248
249         dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
250
251         bglPolygonOffset(0.0);  // resets correctly now, even after calling accumulated offsets
252
253         BLI_edgehash_free(data.eh, NULL);
254 }
255
256 static Material *give_current_material_or_def(Object *ob, int matnr)
257 {
258         extern Material defmaterial;    // render module abuse...
259         Material *ma= give_current_material(ob, matnr);
260
261         return ma?ma:&defmaterial;
262 }
263
264 static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
265 {
266         static int c_textured;
267         static int c_lit;
268         static int c_doublesided;
269         static MTFace *c_texface;
270         static Object *c_litob;
271         static int c_litmatnr;
272         static int c_badtex;
273
274         if (clearcache) {
275                 c_textured= c_lit= c_doublesided= -1;
276                 c_texface= (MTFace*) -1;
277                 c_litob= (Object*) -1;
278                 c_litmatnr= -1;
279                 c_badtex= 0;
280         }
281
282         if (texface) {
283                 lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
284                 textured = textured && (texface->mode&TF_TEX);
285                 doublesided = texface->mode&TF_TWOSIDE;
286         } else {
287                 textured = 0;
288         }
289
290         if (doublesided!=c_doublesided) {
291                 if (doublesided) glDisable(GL_CULL_FACE);
292                 else glEnable(GL_CULL_FACE);
293
294                 c_doublesided= doublesided;
295         }
296
297         if (textured!=c_textured || texface!=c_texface) {
298                 if (textured ) {
299                         c_badtex= !GPU_set_tpage(texface);
300                 } else {
301                         GPU_set_tpage(0);
302                         c_badtex= 0;
303                 }
304                 c_textured= textured;
305                 c_texface= texface;
306         }
307
308         if (c_badtex) lit= 0;
309         if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
310                 if (lit) {
311                         Material *ma= give_current_material_or_def(litob, litmatnr+1);
312                         float spec[4];
313
314                         spec[0]= ma->spec*ma->specr;
315                         spec[1]= ma->spec*ma->specg;
316                         spec[2]= ma->spec*ma->specb;
317                         spec[3]= 1.0;
318
319                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
320                         glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
321                         glEnable(GL_LIGHTING);
322                         glEnable(GL_COLOR_MATERIAL);
323                 }
324                 else {
325                         glDisable(GL_LIGHTING); 
326                         glDisable(GL_COLOR_MATERIAL);
327                 }
328                 c_lit= lit;
329                 c_litob= litob;
330                 c_litmatnr= litmatnr;
331         }
332
333         return c_badtex;
334 }
335
336 /* Icky globals, fix with userdata parameter */
337
338 struct TextureDrawState {
339         Object *ob;
340         int islit, istex;
341         unsigned char obcol[4];
342 } Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
343
344 static void draw_textured_begin(Object *ob)
345 {
346         unsigned char obcol[4];
347         int istex, solidtex= 0;
348
349         if(G.vd->drawtype==OB_SOLID || (ob==G.obedit && G.vd->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(G.scene, ob, G.vd->lay, G.vd->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 || G.vd->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(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_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(ob==G.obedit)
480                 return;
481         else if(ob==OBACT)
482                 if(FACESEL_PAINT_TEST)
483                         return;
484
485         ddm = mesh_get_derived_deform(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(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(ob);
558
559         if(ob==G.obedit) {
560                 dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, G.editMesh);
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_property(ob, "Text")) 
572                 draw_mesh_text(ob, 0);
573
574         draw_textured_end();
575         
576         /* draw edges and selected faces over textured mesh */
577         if(!G.obedit && faceselect)
578                 draw_tfaces3D(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