4 * ***** BEGIN GPL 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.
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.
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.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation, full update, glsl support
25 * ***** END GPL LICENSE BLOCK *****
31 #include "MEM_guardedalloc.h"
33 #include "BLI_blenlib.h"
34 #include "BLI_arithb.h"
35 #include "BLI_edgehash.h"
36 #include "BLI_editVert.h"
38 #include "IMB_imbuf.h"
39 #include "IMB_imbuf_types.h"
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"
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"
60 #include "BKE_material.h"
62 #include "BKE_object.h"
63 #include "BKE_property.h"
64 #include "BKE_utildefines.h"
67 #include "BIF_glutil.h"
69 #include "UI_resources.h"
70 #include "UI_interface_icons.h"
72 #include "GPU_extensions.h"
77 #include "view3d_intern.h" // own include
81 /* Flags for marked edges */
83 eEdge_Visible = (1<<0),
84 eEdge_Select = (1<<1),
87 /* Creates a hash of edges to flags indicating
88 * adjacent tface select/active/etc flags.
90 static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
94 if (!BLI_edgehash_haskey(eh, v0, v1)) {
95 BLI_edgehash_insert(eh, v0, v1, 0);
98 flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
102 static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
104 EdgeHash *eh = BLI_edgehash_new();
109 for (i=0; i<me->totface; i++) {
115 if (!(mf->flag&ME_HIDE)) {
116 unsigned int flags = eEdge_Visible;
117 if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select;
119 get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
120 get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
122 get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
123 get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
125 get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
135 static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
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);
141 if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) {
143 } else if(G.f & G_DRAWEDGES){
144 if (G.f&G_HIDDENEDGES) {
147 return (flags & eEdge_Visible);
150 return (flags & eEdge_Select);
154 static int draw_tfaces3D__setSeamOpts(void *userData, int index)
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);
160 if (med->flag&ME_SEAM) {
161 if (G.f&G_HIDDENEDGES) {
164 return (flags & eEdge_Visible);
171 static int draw_tfaces3D__setSelectOpts(void *userData, int index)
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);
177 return flags & eEdge_Select;
180 static int draw_tfaces3D__setActiveOpts(void *userData, int index)
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);
186 if (flags & eEdge_Select) {
193 static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
195 Mesh *me = (Mesh*)userData;
197 MFace *mface = &me->mface[index];
198 if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL))
199 return 2; /* Don't set color */
204 static void draw_tfaces3D(RegionView3D *rv3d, Object *ob, Mesh *me, DerivedMesh *dm)
206 struct { Mesh *me; EdgeHash *eh; } data;
209 data.eh = get_tface_mesh_marked_edge_info(me);
211 glEnable(GL_DEPTH_TEST);
212 glDisable(GL_LIGHTING);
213 bglPolygonOffset(rv3d->dist, 1.0);
215 /* Draw (Hidden) Edges */
216 UI_ThemeColor(TH_EDGE_FACESEL);
217 dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
220 if(G.f & G_DRAWSEAMS) {
221 UI_ThemeColor(TH_EDGE_SEAM);
224 dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
229 /* Draw Selected Faces */
230 if(G.f & G_DRAWFACES) {
232 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
233 UI_ThemeColor4(TH_FACE_SELECT);
235 dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
240 bglPolygonOffset(rv3d->dist, 1.0);
242 /* Draw Stippled Outline for selected faces */
243 glColor3ub(255, 255, 255);
245 dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
248 dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
250 bglPolygonOffset(rv3d->dist, 0.0); // resets correctly now, even after calling accumulated offsets
252 BLI_edgehash_free(data.eh, NULL);
255 static Material *give_current_material_or_def(Object *ob, int matnr)
257 extern Material defmaterial; // render module abuse...
258 Material *ma= give_current_material(ob, matnr);
260 return ma?ma:&defmaterial;
263 static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
265 static int c_textured;
267 static int c_doublesided;
268 static MTFace *c_texface;
269 static Object *c_litob;
270 static int c_litmatnr;
274 c_textured= c_lit= c_doublesided= -1;
275 c_texface= (MTFace*) -1;
276 c_litob= (Object*) -1;
282 lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
283 textured = textured && (texface->mode&TF_TEX);
284 doublesided = texface->mode&TF_TWOSIDE;
289 if (doublesided!=c_doublesided) {
290 if (doublesided) glDisable(GL_CULL_FACE);
291 else glEnable(GL_CULL_FACE);
293 c_doublesided= doublesided;
296 if (textured!=c_textured || texface!=c_texface) {
298 c_badtex= !GPU_set_tpage(texface);
303 c_textured= textured;
307 if (c_badtex) lit= 0;
308 if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
310 Material *ma= give_current_material_or_def(litob, litmatnr+1);
313 spec[0]= ma->spec*ma->specr;
314 spec[1]= ma->spec*ma->specg;
315 spec[2]= ma->spec*ma->specb;
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);
324 glDisable(GL_LIGHTING);
325 glDisable(GL_COLOR_MATERIAL);
329 c_litmatnr= litmatnr;
335 /* Icky globals, fix with userdata parameter */
337 struct TextureDrawState {
340 unsigned char obcol[4];
341 } Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
343 static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
345 unsigned char obcol[4];
346 int istex, solidtex= 0;
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 */
355 /* draw with lights in the scene otherwise */
356 Gtexdraw.islit= GPU_scene_object_lights(scene, ob, v3d->lay, rv3d->viewmat);
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);
363 glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
364 if(solidtex || v3d->drawtype==OB_TEXTURE) istex= 1;
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);
374 static void draw_textured_end()
376 /* switch off textures */
379 glShadeModel(GL_FLAT);
380 glDisable(GL_CULL_FACE);
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.
387 * It would be better if drawmesh.c kept track
388 * of and restored the light settings it changed.
393 GPU_default_lights();
398 static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
400 if (tface && (tface->mode&TF_INVISIBLE)) return 0;
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 */
409 if (tface) glColor3f(1.0, 1.0, 1.0);
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);
415 return 2; /* Don't set color */
417 return 1; /* Set color from mcol */
421 static int draw_tface_mapped__set_draw(void *userData, int index)
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);
432 static int draw_em_tf_mapped__set_draw(void *userData, int index)
434 EditMesh *em = userData;
435 EditFace *efa= EM_get_face_for_index(index);
440 if (efa==NULL || efa->h)
443 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
444 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
447 return draw_tface__set_draw(tface, mcol, matnr);
450 static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
452 Mesh *me = (Mesh*)userData;
453 MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
454 MFace *mface = (me->mface)? &me->mface[index]: NULL;
456 if ((mface->flag&ME_HIDE) || (tface && (tface->mode&TF_INVISIBLE)))
463 void draw_mesh_text(Scene *scene, Object *ob, int glsl)
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;
474 /* don't draw without tfaces */
478 /* don't draw when editing */
482 if(FACESEL_PAINT_TEST)
485 ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
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;
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;
498 GPU_enable_material(matnr+1, &gattribs);
500 for(i=0; i<gattribs.totlayer; i++) {
501 if(gattribs.layer[i].type == CD_MTFACE) {
502 glattrib = gattribs.layer[i].glindex;
508 badtex = set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE);
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);
520 // The BM_FONT handling is in the gpu module, shared with the
521 // game engine, was duplicated previously
523 set_property_valstr(prop, string);
524 characters = strlen(string);
526 if(!BKE_image_get_ibuf(tface->tpage, NULL))
532 CalcNormFloat(v1, v2, v3, nor);
537 GPU_render_text(tface, tface->mode, string, characters,
538 (unsigned int*)mcol, v1, v2, v3, (mf->v4? v4: NULL), glattrib);
548 void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
552 /* correct for negative scale */
553 if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
554 else glFrontFace(GL_CCW);
556 /* draw the textured mesh */
557 draw_textured_begin(scene, v3d, rv3d, ob);
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);
565 dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
568 dm->drawFacesTex(dm, draw_tface__set_draw);
570 /* draw game engine text hack */
571 if(get_ob_property(ob, "Text"))
572 draw_mesh_text(scene, ob, 0);
576 /* draw edges and selected faces over textured mesh */
577 if(!me->edit_mesh && faceselect)
578 draw_tfaces3D(rv3d, ob, me, dm);
580 /* reset from negative scale correction */
583 /* in editmode, the blend mode needs to be set incase it was ADD */
584 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);