diff options
author | Ton Roosendaal <ton@blender.org> | 2008-12-19 15:14:58 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2008-12-19 15:14:58 +0300 |
commit | d92b45d558b861ef3c314f1d9c926113aa36326c (patch) | |
tree | d057b1bf627026fc1bbecec74e4625ed737d5229 | |
parent | c752ec9fc458f6fd1fc0ae7a156d33bf86e73eff (diff) |
2.5
Drawing code for space_view3d module.
It's still not cleaned, have to check on context usage still.
Also missing is editmodes, armatures, and probably more.
Known issue: splitting to 2nd window gives bad opengl lighting.
Picture for fun:
http://www.blender.org/bf/rt2.jpg
Current stat: brought back almost 10k lines! :)
-rw-r--r-- | source/blender/editors/include/BIF_retopo.h | 110 | ||||
-rw-r--r-- | source/blender/editors/include/ED_types.h | 5 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/Makefile | 1 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/SConscript | 1 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawmesh.c | 579 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 5475 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_draw.c | 385 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_edit.c | 1086 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_header.c | 1 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_intern.h | 48 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 941 | ||||
-rw-r--r-- | source/blender/windowmanager/SConscript | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/Makefile | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 12 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_subwindow.c | 2 |
16 files changed, 8510 insertions, 141 deletions
diff --git a/source/blender/editors/include/BIF_retopo.h b/source/blender/editors/include/BIF_retopo.h new file mode 100644 index 00000000000..cc2fda56b07 --- /dev/null +++ b/source/blender/editors/include/BIF_retopo.h @@ -0,0 +1,110 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BIF_RETOPO_H +#define BIF_RETOPO_H + +#include "DNA_vec_types.h" + +/* For bglMats */ +#include "BIF_glutil.h" + +struct EditVert; +struct Mesh; +struct View3D; + +typedef struct RetopoViewData { + bglMats mats; + + char queue_matrix_update; +} RetopoViewData; + +typedef struct RetopoPaintPoint { + struct RetopoPaintPoint *next, *prev; + vec2s loc; + short index; + float co[3]; + struct EditVert *eve; +} RetopoPaintPoint; + +typedef struct RetopoPaintLine { + struct RetopoPaintLine *next, *prev; + ListBase points; + ListBase hitlist; /* RetopoPaintHit */ + RetopoPaintPoint *cyclic; +} RetopoPaintLine; + +typedef struct RetopoPaintSel { + struct RetopoPaintSel *next, *prev; + RetopoPaintLine *line; + char first; +} RetopoPaintSel; + +typedef struct RetopoPaintData { + char in_drag; + short sloc[2]; + + ListBase lines; + ListBase intersections; /* RetopoPaintPoint */ + + short seldist; + RetopoPaintSel nearest; + + struct View3D *paint_v3d; +} RetopoPaintData; + +RetopoPaintData *get_retopo_paint_data(void); + +char retopo_mesh_check(void); +char retopo_curve_check(void); + +void retopo_end_okee(void); + +void retopo_free_paint_data(RetopoPaintData *rpd); +void retopo_free_paint(void); + +char retopo_mesh_paint_check(void); +void retopo_paint_view_update(struct View3D *v3d); +void retopo_force_update(void); +void retopo_paint_toggle(void*,void*); +char retopo_paint(const unsigned short event); +void retopo_draw_paint_lines(void); +RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd); + +void retopo_toggle(void*,void*); +void retopo_do_vert(struct View3D *v3d, float *v); +void retopo_do_all(void); +void retopo_do_all_cb(void *, void *); +void retopo_queue_updates(struct View3D *v3d); + +void retopo_matrix_update(struct View3D *v3d); + +void retopo_free_view_data(struct View3D *v3d); + +#endif diff --git a/source/blender/editors/include/ED_types.h b/source/blender/editors/include/ED_types.h index 7b19341fb9e..ec5dce0c70d 100644 --- a/source/blender/editors/include/ED_types.h +++ b/source/blender/editors/include/ED_types.h @@ -31,8 +31,9 @@ /* **************** GENERAL EDITOR-WIDE TYPES AND DEFINES ************************** */ /* old blender defines... should be depricated? */ -#define SELECT 1 -#define ACTIVE 2 +#define DESELECT 0 +#define SELECT 1 +#define ACTIVE 2 #endif /* ED_TYPES_H */ diff --git a/source/blender/editors/space_view3d/Makefile b/source/blender/editors/space_view3d/Makefile index e097d041a37..7a5f609a187 100644 --- a/source/blender/editors/space_view3d/Makefile +++ b/source/blender/editors/space_view3d/Makefile @@ -48,6 +48,7 @@ CPPFLAGS += -I../../blenlib CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../imbuf CPPFLAGS += -I../../python +CPPFLAGS += -I../../gpu CPPFLAGS += -I../../render/extern/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript index 5d30ae91deb..77cf03820ed 100644 --- a/source/blender/editors/space_view3d/SConscript +++ b/source/blender/editors/space_view3d/SConscript @@ -6,5 +6,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include #/intern/guardedalloc #intern/bmfont' +incs += ' ../../gpu' env.BlenderLib ( 'bf_editors_space_view3d', sources, Split(incs), [], libtype=['core','intern'], priority=[35, 40] ) diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c new file mode 100644 index 00000000000..01740d2b3b4 --- /dev/null +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -0,0 +1,579 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, full update, glsl support + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_edgehash.h" +#include "BLI_editVert.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "DNA_image_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_property_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_bmfont.h" +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_DerivedMesh.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_property.h" +#include "BKE_utildefines.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_resources.h" +#include "UI_interface_icons.h" + +#include "GPU_extensions.h" +#include "GPU_draw.h" + +#include "view3d_intern.h" // own include + +/***/ + + /* Flags for marked edges */ +enum { + eEdge_Visible = (1<<0), + eEdge_Select = (1<<1), +}; + + /* Creates a hash of edges to flags indicating + * adjacent tface select/active/etc flags. + */ +static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags) +{ + int *flags_p; + + if (!BLI_edgehash_haskey(eh, v0, v1)) { + BLI_edgehash_insert(eh, v0, v1, 0); + } + + flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1); + *flags_p |= flags; +} + +static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me) +{ + EdgeHash *eh = BLI_edgehash_new(); + int i; + MFace *mf; + MTFace *tf = NULL; + + for (i=0; i<me->totface; i++) { + mf = &me->mface[i]; + if (me->mtface) + tf = &me->mtface[i]; + + if (mf->v3) { + if (!(mf->flag&ME_HIDE)) { + unsigned int flags = eEdge_Visible; + if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select; + + get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags); + get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags); + if (mf->v4) { + get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags); + get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags); + } else { + get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags); + } + } + } + } + + return eh; +} + + +static int draw_tfaces3D__setHiddenOpts(void *userData, int index) +{ + struct { Mesh *me; EdgeHash *eh; } *data = userData; + MEdge *med = &data->me->medge[index]; + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + + if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) { + return 0; + } else if(G.f & G_DRAWEDGES){ + if (G.f&G_HIDDENEDGES) { + return 1; + } else { + return (flags & eEdge_Visible); + } + } else { + return (flags & eEdge_Select); + } +} +static int draw_tfaces3D__setSeamOpts(void *userData, int index) +{ + struct { Mesh *me; EdgeHash *eh; } *data = userData; + MEdge *med = &data->me->medge[index]; + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + + if (med->flag&ME_SEAM) { + if (G.f&G_HIDDENEDGES) { + return 1; + } else { + return (flags & eEdge_Visible); + } + } else { + return 0; + } +} +static int draw_tfaces3D__setSelectOpts(void *userData, int index) +{ + struct { Mesh *me; EdgeHash *eh; } *data = userData; + MEdge *med = &data->me->medge[index]; + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + + return flags & eEdge_Select; +} +static int draw_tfaces3D__setActiveOpts(void *userData, int index) +{ + struct { Mesh *me; EdgeHash *eh; } *data = userData; + MEdge *med = &data->me->medge[index]; + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + + if (flags & eEdge_Select) { + return 1; + } else { + return 0; + } +} +static int draw_tfaces3D__drawFaceOpts(void *userData, int index) +{ + Mesh *me = (Mesh*)userData; + + MFace *mface = &me->mface[index]; + if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL)) + return 2; /* Don't set color */ + else + return 0; +} +static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm) +{ + struct { Mesh *me; EdgeHash *eh; } data; + + data.me = me; + data.eh = get_tface_mesh_marked_edge_info(me); + + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + bglPolygonOffset(1.0); + + /* Draw (Hidden) Edges */ + UI_ThemeColor(TH_EDGE_FACESEL); + dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data); + + /* Draw Seams */ + if(G.f & G_DRAWSEAMS) { + UI_ThemeColor(TH_EDGE_SEAM); + glLineWidth(2); + + dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data); + + glLineWidth(1); + } + + /* Draw Selected Faces */ + if(G.f & G_DRAWFACES) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + UI_ThemeColor4(TH_FACE_SELECT); + + dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me); + + glDisable(GL_BLEND); + } + + bglPolygonOffset(1.0); + + /* Draw Stippled Outline for selected faces */ + glColor3ub(255, 255, 255); + setlinestyle(1); + dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data); + setlinestyle(0); + + dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data); + + bglPolygonOffset(0.0); // resets correctly now, even after calling accumulated offsets + + BLI_edgehash_free(data.eh, NULL); +} + +static Material *give_current_material_or_def(Object *ob, int matnr) +{ + extern Material defmaterial; // render module abuse... + Material *ma= give_current_material(ob, matnr); + + return ma?ma:&defmaterial; +} + +static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided) +{ + static int c_textured; + static int c_lit; + static int c_doublesided; + static MTFace *c_texface; + static Object *c_litob; + static int c_litmatnr; + static int c_badtex; + + if (clearcache) { + c_textured= c_lit= c_doublesided= -1; + c_texface= (MTFace*) -1; + c_litob= (Object*) -1; + c_litmatnr= -1; + c_badtex= 0; + } + + if (texface) { + lit = lit && (lit==-1 || texface->mode&TF_LIGHT); + textured = textured && (texface->mode&TF_TEX); + doublesided = texface->mode&TF_TWOSIDE; + } else { + textured = 0; + } + + if (doublesided!=c_doublesided) { + if (doublesided) glDisable(GL_CULL_FACE); + else glEnable(GL_CULL_FACE); + + c_doublesided= doublesided; + } + + if (textured!=c_textured || texface!=c_texface) { + if (textured ) { + c_badtex= !GPU_set_tpage(texface); + } else { + GPU_set_tpage(0); + c_badtex= 0; + } + c_textured= textured; + c_texface= texface; + } + + if (c_badtex) lit= 0; + if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) { + if (lit) { + Material *ma= give_current_material_or_def(litob, litmatnr+1); + float spec[4]; + + spec[0]= ma->spec*ma->specr; + spec[1]= ma->spec*ma->specg; + spec[2]= ma->spec*ma->specb; + spec[3]= 1.0; + + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + } + else { + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + } + c_lit= lit; + c_litob= litob; + c_litmatnr= litmatnr; + } + + return c_badtex; +} + +/* Icky globals, fix with userdata parameter */ + +struct TextureDrawState { + Object *ob; + int islit, istex; + unsigned char obcol[4]; +} Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}}; + +static void draw_textured_begin(Scene *scene, View3D *v3d, Object *ob) +{ + unsigned char obcol[4]; + int istex, solidtex= 0; + + if(v3d->drawtype==OB_SOLID || (ob==G.obedit && v3d->drawtype!=OB_TEXTURE)) { + /* draw with default lights in solid draw mode and edit mode */ + solidtex= 1; + Gtexdraw.islit= -1; + } + else + /* draw with lights in the scene otherwise */ + Gtexdraw.islit= GPU_scene_object_lights(scene, ob, v3d->lay, v3d->viewmat); + + obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255); + obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255); + obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255); + obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255); + + glCullFace(GL_BACK); glEnable(GL_CULL_FACE); + if(solidtex || v3d->drawtype==OB_TEXTURE) istex= 1; + else istex= 0; + + Gtexdraw.ob = ob; + Gtexdraw.istex = istex; + memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); + set_draw_settings_cached(1, 0, 0, Gtexdraw.islit, 0, 0, 0); + glShadeModel(GL_SMOOTH); +} + +static void draw_textured_end() +{ + /* switch off textures */ + GPU_set_tpage(0); + + glShadeModel(GL_FLAT); + glDisable(GL_CULL_FACE); + + /* XXX, bad patch - GPU_default_lights() calls + * glLightfv(GL_LIGHT_POSITION, ...) which + * is transformed by the current matrix... we + * need to make sure that matrix is identity. + * + * It would be better if drawmesh.c kept track + * of and restored the light settings it changed. + * - zr + */ + glPushMatrix(); + glLoadIdentity(); + GPU_default_lights(); + glPopMatrix(); +} + + +static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr) +{ + if (tface && (tface->mode&TF_INVISIBLE)) return 0; + + if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) { + glColor3ub(0xFF, 0x00, 0xFF); + return 2; /* Don't set color */ + } else if (tface && tface->mode&TF_OBCOL) { + glColor3ubv(Gtexdraw.obcol); + return 2; /* Don't set color */ + } else if (!mcol) { + if (tface) glColor3f(1.0, 1.0, 1.0); + else { + Material *ma= give_current_material(Gtexdraw.ob, matnr+1); + if(ma) glColor3f(ma->r, ma->g, ma->b); + else glColor3f(1.0, 1.0, 1.0); + } + return 2; /* Don't set color */ + } else { + return 1; /* Set color from mcol */ + } +} + +static int draw_tface_mapped__set_draw(void *userData, int index) +{ + Mesh *me = (Mesh*)userData; + MTFace *tface = (me->mtface)? &me->mtface[index]: NULL; + MFace *mface = (me->mface)? &me->mface[index]: NULL; + MCol *mcol = (me->mcol)? &me->mcol[index]: NULL; + int matnr = me->mface[index].mat_nr; + if (mface && mface->flag&ME_HIDE) return 0; + return draw_tface__set_draw(tface, mcol, matnr); +} + +static int draw_em_tf_mapped__set_draw(void *userData, int index) +{ + EditMesh *em = userData; + EditFace *efa= NULL; // XXX = EM_get_face_for_index(index); + MTFace *tface; + MCol *mcol; + int matnr; + + if (efa==NULL || efa->h) + return 0; + + tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + matnr = efa->mat_nr; + + return draw_tface__set_draw(tface, mcol, matnr); +} + +static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) +{ + Mesh *me = (Mesh*)userData; + MTFace *tface = (me->mtface)? &me->mtface[index]: NULL; + MFace *mface = (me->mface)? &me->mface[index]: NULL; + + if ((mface->flag&ME_HIDE) || (tface && (tface->mode&TF_INVISIBLE))) + return 0; + + *drawSmooth_r = 1; + return 1; +} + +void draw_mesh_text(Object *ob, int glsl) +{ + Mesh *me = ob->data; + DerivedMesh *ddm; + MFace *mf, *mface= me->mface; + MTFace *tface= me->mtface; + MCol *mcol= me->mcol; /* why does mcol exist? */ + bProperty *prop = get_ob_property(ob, "Text"); + GPUVertexAttribs gattribs; + int a, totface= me->totface; + + /* don't draw without tfaces */ + if(!tface) + return; + + /* don't draw when editing */ + if(ob==G.obedit) + return; + else if(ob==OBACT) + if(FACESEL_PAINT_TEST) + return; + + ddm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + + for(a=0, mf=mface; a<totface; a++, tface++, mf++) { + int mode= tface->mode; + int matnr= mf->mat_nr; + int mf_smooth= mf->flag & ME_SMOOTH; + + if (!(mf->flag&ME_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) { + float v1[3], v2[3], v3[3], v4[3]; + char string[MAX_PROPSTRING]; + int characters, i, glattrib= -1, badtex= 0; + + if(glsl) { + GPU_enable_material(matnr+1, &gattribs); + + for(i=0; i<gattribs.totlayer; i++) { + if(gattribs.layer[i].type == CD_MTFACE) { + glattrib = gattribs.layer[i].glindex; + break; + } + } + } + else { + badtex = set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE); + if (badtex) { + if (mcol) mcol+=4; + continue; + } + } + + ddm->getVertCo(ddm, mf->v1, v1); + ddm->getVertCo(ddm, mf->v2, v2); + ddm->getVertCo(ddm, mf->v3, v3); + if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4); + + // The BM_FONT handling is in the gpu module, shared with the + // game engine, was duplicated previously + + set_property_valstr(prop, string); + characters = strlen(string); + + if(!BKE_image_get_ibuf(tface->tpage, NULL)) + characters = 0; + + if (!mf_smooth) { + float nor[3]; + + CalcNormFloat(v1, v2, v3, nor); + + glNormal3fv(nor); + } + + GPU_render_text(tface, tface->mode, string, characters, + (unsigned int*)mcol, v1, v2, v3, (mf->v4? v4: NULL), glattrib); + } + if (mcol) { + mcol+=4; + } + } + + ddm->release(ddm); +} + +void draw_mesh_textured(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int faceselect) +{ + Mesh *me= ob->data; + + /* correct for negative scale */ + if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); + else glFrontFace(GL_CCW); + + /* draw the textured mesh */ + draw_textured_begin(scene, v3d, ob); + + if(ob==G.obedit) { + dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, G.editMesh); + } else if(faceselect) { + if(G.f & G_WEIGHTPAINT) + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1); + else + dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me); + } + else + dm->drawFacesTex(dm, draw_tface__set_draw); + + /* draw game engine text hack */ + if(get_ob_property(ob, "Text")) + draw_mesh_text(ob, 0); + + draw_textured_end(); + + /* draw edges and selected faces over textured mesh */ + if(!G.obedit && faceselect) + draw_tfaces3D(ob, me, dm); + + /* reset from negative scale correction */ + glFrontFace(GL_CCW); + + /* in editmode, the blend mode needs to be set incase it was ADD */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c new file mode 100644 index 00000000000..f5a2cd9df00 --- /dev/null +++ b/source/blender/editors/space_view3d/drawobject.c @@ -0,0 +1,5475 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, full recode and added functions + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" + +#include "IMB_imbuf.h" + + +#include "MTC_matrixops.h" + +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_constraint_types.h" // for drawing constraint +#include "DNA_effect_types.h" +#include "DNA_ipo_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_meta_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_particle_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" +// FSPARTICLE +#include "DNA_object_fluidsim.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_edgehash.h" +#include "BLI_rand.h" + +#include "BKE_anim.h" //for the where_on_path function +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_constraint.h" // for the get_constraint_target function +#include "BKE_DerivedMesh.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_font.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lattice.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_mball.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_property.h" +#include "BKE_utildefines.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_draw.h" +#include "GPU_material.h" +#include "GPU_extensions.h" + +#include "ED_types.h" +#include "ED_util.h" + +#include "UI_resources.h" +#include "UI_interface_icons.h" + +#include "WM_api.h" + +#include "view3d_intern.h" // own include + + +/* pretty stupid */ +/* extern Lattice *editLatt; already in BKE_lattice.h */ +/* editcurve.c */ +extern ListBase editNurb; +/* editmball.c */ +extern ListBase editelems; + +static void draw_bounding_volume(Object *ob); + +static void drawcube_size(float size); +static void drawcircle_size(float size); +static void draw_empty_sphere(float size); +static void draw_empty_cone(float size); + +EditVert *EM_get_vert_for_index(int x) {return 0;} // XXX +EditEdge *EM_get_edge_for_index(int x) {return 0;} // XXX +EditFace *EM_get_face_for_index(int x) {return 0;} // XXX +void EM_init_index_arrays(int x, int y, int z) {} // XXX +void EM_free_index_arrays(void) {} // XXX +#define EM_FGON 0 +EditFace *EM_get_actFace(int x) {return NULL;} // XXX +int draw_armature(Base *base, int x, int y) {return 0;} // XXX +int em_solidoffs; // XXX +int em_wireoffs; +int em_vertoffs; + +/* check for glsl drawing */ + +int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt) +{ + if(!GPU_extensions_minimum_support()) + return 0; + if(G.f & G_PICKSEL) + return 0; + if(!CHECK_OB_DRAWTEXTURE(v3d, dt)) + return 0; + if(ob==OBACT && (G.f & G_WEIGHTPAINT)) + return 0; + + return ((G.fileflags & G_FILE_GAME_MAT) && + (G.fileflags & G_FILE_GAME_MAT_GLSL) && (dt >= OB_SHADED)); +} + +static int check_material_alpha(Base *base, Object *ob, int glsl) +{ + if(base->flag & OB_FROMDUPLI) + return 0; + + if(G.f & G_PICKSEL) + return 0; + + if(G.obedit && G.obedit->data==ob->data) + return 0; + + return (glsl || (ob->dtx & OB_DRAWTRANSP)); +} + + /***/ +static unsigned int colortab[24]= + {0x0, 0xFF88FF, 0xFFBBFF, + 0x403000, 0xFFFF88, 0xFFFFBB, + 0x104040, 0x66CCCC, 0x77CCCC, + 0x104010, 0x55BB55, 0x66FF66, + 0xFFFFFF +}; + + +static float cube[8][3] = { + {-1.0, -1.0, -1.0}, + {-1.0, -1.0, 1.0}, + {-1.0, 1.0, 1.0}, + {-1.0, 1.0, -1.0}, + { 1.0, -1.0, -1.0}, + { 1.0, -1.0, 1.0}, + { 1.0, 1.0, 1.0}, + { 1.0, 1.0, -1.0}, +}; + +/* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */ +/* 32 values of sin function (still same result!) */ +static float sinval[32] = { + 0.00000000, + 0.20129852, + 0.39435585, + 0.57126821, + 0.72479278, + 0.84864425, + 0.93775213, + 0.98846832, + 0.99871650, + 0.96807711, + 0.89780453, + 0.79077573, + 0.65137248, + 0.48530196, + 0.29936312, + 0.10116832, + -0.10116832, + -0.29936312, + -0.48530196, + -0.65137248, + -0.79077573, + -0.89780453, + -0.96807711, + -0.99871650, + -0.98846832, + -0.93775213, + -0.84864425, + -0.72479278, + -0.57126821, + -0.39435585, + -0.20129852, + 0.00000000 +}; + +/* 32 values of cos function (still same result!) */ +static float cosval[32] ={ + 1.00000000, + 0.97952994, + 0.91895781, + 0.82076344, + 0.68896691, + 0.52896401, + 0.34730525, + 0.15142777, + -0.05064916, + -0.25065253, + -0.44039415, + -0.61210598, + -0.75875812, + -0.87434661, + -0.95413925, + -0.99486932, + -0.99486932, + -0.95413925, + -0.87434661, + -0.75875812, + -0.61210598, + -0.44039415, + -0.25065253, + -0.05064916, + 0.15142777, + 0.34730525, + 0.52896401, + 0.68896691, + 0.82076344, + 0.91895781, + 0.97952994, + 1.00000000 +}; + +/* flag is same as for draw_object */ +void drawaxes(float size, int flag, char drawtype) +{ + int axis; + float v1[3]= {0.0, 0.0, 0.0}; + float v2[3]= {0.0, 0.0, 0.0}; + float v3[3]= {0.0, 0.0, 0.0}; + + if(G.f & G_RENDER_SHADOW) + return; + + switch(drawtype) { + + case OB_PLAINAXES: + for (axis=0; axis<3; axis++) { + float v1[3]= {0.0, 0.0, 0.0}; + float v2[3]= {0.0, 0.0, 0.0}; + + glBegin(GL_LINES); + + v1[axis]= size; + v2[axis]= -size; + glVertex3fv(v1); + glVertex3fv(v2); + + glEnd(); + } + break; + case OB_SINGLE_ARROW: + + glBegin(GL_LINES); + /* in positive z direction only */ + v1[2]= size; + glVertex3fv(v1); + glVertex3fv(v2); + glEnd(); + + /* square pyramid */ + glBegin(GL_TRIANGLES); + + v2[0]= size*0.035; v2[1] = size*0.035; + v3[0]= size*-0.035; v3[1] = size*0.035; + v2[2]= v3[2]= size*0.75; + + for (axis=0; axis<4; axis++) { + if (axis % 2 == 1) { + v2[0] *= -1; + v3[1] *= -1; + } else { + v2[1] *= -1; + v3[0] *= -1; + } + + glVertex3fv(v1); + glVertex3fv(v2); + glVertex3fv(v3); + + } + glEnd(); + + break; + case OB_CUBE: + drawcube_size(size); + break; + + case OB_CIRCLE: + drawcircle_size(size); + break; + + case OB_EMPTY_SPHERE: + draw_empty_sphere(size); + break; + + case OB_EMPTY_CONE: + draw_empty_cone(size); + break; + + case OB_ARROWS: + default: + for (axis=0; axis<3; axis++) { + float v1[3]= {0.0, 0.0, 0.0}; + float v2[3]= {0.0, 0.0, 0.0}; + int arrow_axis= (axis==0)?1:0; + + glBegin(GL_LINES); + + v2[axis]= size; + glVertex3fv(v1); + glVertex3fv(v2); + + v1[axis]= size*0.8; + v1[arrow_axis]= -size*0.125; + glVertex3fv(v1); + glVertex3fv(v2); + + v1[arrow_axis]= size*0.125; + glVertex3fv(v1); + glVertex3fv(v2); + + glEnd(); + + v2[axis]+= size*0.125; + glRasterPos3fv(v2); + + // patch for 3d cards crashing on glSelect for text drawing (IBM) + if((flag & DRAW_PICKING) == 0) { + if (axis==0) + BMF_DrawString(G.font, "x"); + else if (axis==1) + BMF_DrawString(G.font, "y"); + else + BMF_DrawString(G.font, "z"); + } + } + break; + } +} + +void drawcircball(int mode, float *cent, float rad, float tmat[][4]) +{ + float vec[3], vx[3], vy[3]; + int a, tot=32; + + VECCOPY(vx, tmat[0]); + VECCOPY(vy, tmat[1]); + VecMulf(vx, rad); + VecMulf(vy, rad); + + glBegin(mode); + for(a=0; a<tot; a++) { + vec[0]= cent[0] + *(sinval+a) * vx[0] + *(cosval+a) * vy[0]; + vec[1]= cent[1] + *(sinval+a) * vx[1] + *(cosval+a) * vy[1]; + vec[2]= cent[2] + *(sinval+a) * vx[2] + *(cosval+a) * vy[2]; + glVertex3fv(vec); + } + glEnd(); +} + +/* circle for object centers, special_color is for library or ob users */ +static void drawcentercircle(View3D *v3d, float *vec, int selstate, int special_color) +{ + float size; + + size= v3d->persmat[0][3]*vec[0]+ v3d->persmat[1][3]*vec[1]+ v3d->persmat[2][3]*vec[2]+ v3d->persmat[3][3]; + size*= v3d->pixsize*((float)U.obcenter_dia*0.5f); + + /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */ + if(v3d->zbuf) glDepthFunc(GL_ALWAYS); + glEnable(GL_BLEND); + + if(special_color) { + if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); + + else glColor4ub(0x55, 0xCC, 0xCC, 155); + } + else { + if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80); + else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80); + else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); + } + drawcircball(GL_POLYGON, vec, size, v3d->viewinv); + + UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); + drawcircball(GL_LINE_LOOP, vec, size, v3d->viewinv); + + glDisable(GL_BLEND); + if(v3d->zbuf) glDepthFunc(GL_LEQUAL); +} + + +void drawsolidcube(float size) +{ + float n[3]; + + glPushMatrix(); + glScalef(size, size, size); + + n[0]=0; n[1]=0; n[2]=0; + glBegin(GL_QUADS); + n[0]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); + n[0]=0; + glEnd(); + + glBegin(GL_QUADS); + n[1]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); + n[1]=0; + glEnd(); + + glBegin(GL_QUADS); + n[0]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); + n[0]=0; + glEnd(); + + glBegin(GL_QUADS); + n[1]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); + n[1]=0; + glEnd(); + + glBegin(GL_QUADS); + n[2]= 1.0; + glNormal3fv(n); + glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); + n[2]=0; + glEnd(); + + glBegin(GL_QUADS); + n[2]= -1.0; + glNormal3fv(n); + glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); + glEnd(); + + glPopMatrix(); +} + +static void drawcube(void) +{ + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]); + glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]); + glVertex3fv(cube[7]); glVertex3fv(cube[4]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[1]); glVertex3fv(cube[5]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[2]); glVertex3fv(cube[6]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[3]); glVertex3fv(cube[7]); + glEnd(); +} + +/* draws a cube on given the scaling of the cube, assuming that + * all required matrices have been set (used for drawing empties) + */ +static void drawcube_size(float size) +{ + glBegin(GL_LINE_STRIP); + glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size); + glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size); + glVertex3f(size,size,-size); glVertex3f(size,-size,-size); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3f(-size,-size,size); glVertex3f(size,-size,size); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3f(-size,size,size); glVertex3f(size,size,size); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3f(-size,size,-size); glVertex3f(size,size,-size); + glEnd(); +} + +/* this is an unused (old) cube-drawing function based on a given size */ +#if 0 +static void drawcube_size(float *size) +{ + + glPushMatrix(); + glScalef(size[0], size[1], size[2]); + + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]); + glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]); + glVertex3fv(cube[7]); glVertex3fv(cube[4]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[1]); glVertex3fv(cube[5]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[2]); glVertex3fv(cube[6]); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3fv(cube[3]); glVertex3fv(cube[7]); + glEnd(); + + glPopMatrix(); +} +#endif + +static void drawshadbuflimits(Lamp *la, float mat[][4]) +{ + float sta[3], end[3], lavec[3]; + + lavec[0]= -mat[2][0]; + lavec[1]= -mat[2][1]; + lavec[2]= -mat[2][2]; + Normalize(lavec); + + sta[0]= mat[3][0]+ la->clipsta*lavec[0]; + sta[1]= mat[3][1]+ la->clipsta*lavec[1]; + sta[2]= mat[3][2]+ la->clipsta*lavec[2]; + + end[0]= mat[3][0]+ la->clipend*lavec[0]; + end[1]= mat[3][1]+ la->clipend*lavec[1]; + end[2]= mat[3][2]+ la->clipend*lavec[2]; + + + glBegin(GL_LINE_STRIP); + glVertex3fv(sta); + glVertex3fv(end); + glEnd(); + + glPointSize(3.0); + bglBegin(GL_POINTS); + bglVertex3fv(sta); + bglVertex3fv(end); + bglEnd(); + glPointSize(1.0); +} + + + +static void spotvolume(float *lvec, float *vvec, float inp) +{ + /* camera is at 0,0,0 */ + float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle; + + Normalize(lvec); + Normalize(vvec); /* is this the correct vector ? */ + + Crossf(temp,vvec,lvec); /* equation for a plane through vvec en lvec */ + Crossf(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */ + + Normalize(plane); + + /* now we've got two equations: one of a cone and one of a plane, but we have + three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */ + + /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */ + /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/ + + /* translating this comment to english didnt really help me understanding the math! :-) (ton) */ + + q[1] = plane[1] ; + q[2] = -plane[0] ; + q[3] = 0 ; + Normalize(&q[1]); + + angle = saacos(plane[2])/2.0; + co = cos(angle); + si = sqrt(1-co*co); + + q[0] = co; + q[1] *= si; + q[2] *= si; + q[3] = 0; + + QuatToMat3(q,mat1); + + /* rotate lamp vector now over acos(inp) degrees */ + + vvec[0] = lvec[0] ; + vvec[1] = lvec[1] ; + vvec[2] = lvec[2] ; + + Mat3One(mat2); + co = inp; + si = sqrt(1-inp*inp); + + mat2[0][0] = co; + mat2[1][0] = -si; + mat2[0][1] = si; + mat2[1][1] = co; + Mat3MulMat3(mat3,mat2,mat1); + + mat2[1][0] = si; + mat2[0][1] = -si; + Mat3MulMat3(mat4,mat2,mat1); + Mat3Transp(mat1); + + Mat3MulMat3(mat2,mat1,mat3); + Mat3MulVecfl(mat2,lvec); + Mat3MulMat3(mat2,mat1,mat4); + Mat3MulVecfl(mat2,vvec); + + return; +} + +static void drawlamp(const bContext *C, Scene *scene, View3D *v3d, Object *ob) +{ + Lamp *la; + float vec[3], lvec[3], vvec[3], circrad, x,y,z; + float pixsize, lampsize; + float imat[4][4], curcol[4]; + char col[4]; + + if(G.f & G_RENDER_SHADOW) + return; + + la= ob->data; + + /* we first draw only the screen aligned & fixed scale stuff */ + glPushMatrix(); + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + /* lets calculate the scale: */ + pixsize= v3d->persmat[0][3]*ob->obmat[3][0]+ v3d->persmat[1][3]*ob->obmat[3][1]+ v3d->persmat[2][3]*ob->obmat[3][2]+ v3d->persmat[3][3]; + pixsize*= v3d->pixsize; + lampsize= pixsize*((float)U.obcenter_dia*0.5f); + + /* and view aligned matrix: */ + Mat4CpyMat4(imat, v3d->viewinv); + Normalize(imat[0]); + Normalize(imat[1]); + + /* for AA effects */ + glGetFloatv(GL_CURRENT_COLOR, curcol); + curcol[3]= 0.6; + glColor4fv(curcol); + + if(ob->id.us>1) { + if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155); + else glColor4ub(0x77, 0xCC, 0xCC, 155); + } + + /* Inner Circle */ + VECCOPY(vec, ob->obmat[3]); + glEnable(GL_BLEND); + drawcircball(GL_LINE_LOOP, vec, lampsize, imat); + glDisable(GL_BLEND); + drawcircball(GL_POLYGON, vec, lampsize, imat); + + /* restore */ + if(ob->id.us>1) + glColor4fv(curcol); + + /* Outer circle */ + circrad = 3.0f*lampsize; + drawcircball(GL_LINE_LOOP, vec, circrad, imat); + + setlinestyle(3); + + /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ + if (la->type!=LA_HEMI) { + if ((la->mode & LA_SHAD_RAY) || + ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT)) ) + { + drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat); + } + } + + /* draw the pretty sun rays */ + if(la->type==LA_SUN) { + float v1[3], v2[3], mat[3][3]; + short axis; + + /* setup a 45 degree rotation matrix */ + VecRotToMat3(imat[2], M_PI/4.0f, mat); + + /* vectors */ + VECCOPY(v1, imat[0]); + VecMulf(v1, circrad*1.2f); + VECCOPY(v2, imat[0]); + VecMulf(v2, circrad*2.5f); + + /* center */ + glTranslatef(vec[0], vec[1], vec[2]); + + setlinestyle(3); + + glBegin(GL_LINES); + for (axis=0; axis<8; axis++) { + glVertex3fv(v1); + glVertex3fv(v2); + Mat3MulVecfl(mat, v1); + Mat3MulVecfl(mat, v2); + } + glEnd(); + + glTranslatef(-vec[0], -vec[1], -vec[2]); + + } + + if (la->type==LA_LOCAL) { + if(la->mode & LA_SPHERE) { + drawcircball(GL_LINE_LOOP, vec, la->dist, imat); + } + /* yafray: for photonlight also draw lightcone as for spot */ + } + + glPopMatrix(); /* back in object space */ + vec[0]= vec[1]= vec[2]= 0.0f; + + if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) { + lvec[0]=lvec[1]= 0.0; + lvec[2] = 1.0; + x = v3d->persmat[0][2]; + y = v3d->persmat[1][2]; + z = v3d->persmat[2][2]; + vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2]; + vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2]; + vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2]; + + y = cos( M_PI*la->spotsize/360.0 ); + spotvolume(lvec, vvec, y); + x = -la->dist; + lvec[0] *= x ; + lvec[1] *= x ; + lvec[2] *= x; + vvec[0] *= x ; + vvec[1] *= x ; + vvec[2] *= x; + + /* draw the angled sides of the cone */ + glBegin(GL_LINE_STRIP); + glVertex3fv(vvec); + glVertex3fv(vec); + glVertex3fv(lvec); + glEnd(); + + z = x*sqrt(1.0 - y*y); + x *= y; + + /* draw the circle/square at the end of the cone */ + glTranslatef(0.0, 0.0 , x); + if(la->mode & LA_SQUARE) { + vvec[0]= fabs(z); + vvec[1]= fabs(z); + vvec[2]= 0.0; + glBegin(GL_LINE_LOOP); + glVertex3fv(vvec); + vvec[1]= -fabs(z); + glVertex3fv(vvec); + vvec[0]= -fabs(z); + glVertex3fv(vvec); + vvec[1]= fabs(z); + glVertex3fv(vvec); + glEnd(); + } + else circ(0.0, 0.0, fabs(z)); + + /* draw the circle/square representing spotbl */ + if(la->type==LA_SPOT) { + float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2)); + /* make sure the line is always visible - prevent it from reaching the outer border (or 0) + * values are kinda arbitrary - just what seemed to work well */ + if (spotblcirc == 0) spotblcirc = 0.15; + else if (spotblcirc == fabs(z)) spotblcirc = fabs(z) - 0.07; + circ(0.0, 0.0, spotblcirc); + } + + } + else if ELEM(la->type, LA_HEMI, LA_SUN) { + + /* draw the line from the circle along the dist */ + glBegin(GL_LINE_STRIP); + vec[2] = -circrad; + glVertex3fv(vec); + vec[2]= -la->dist; + glVertex3fv(vec); + glEnd(); + + if(la->type==LA_HEMI) { + /* draw the hemisphere curves */ + short axis, steps, dir; + float outdist, zdist, mul; + vec[0]=vec[1]=vec[2]= 0.0; + outdist = 0.14; mul = 1.4; dir = 1; + + setlinestyle(4); + /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */ + for (axis=0; axis<4; axis++) { + float v[3]= {0.0, 0.0, 0.0}; + zdist = 0.02; + + glBegin(GL_LINE_STRIP); + + for (steps=0; steps<6; steps++) { + if (axis == 0 || axis == 1) { /* x axis up, x axis down */ + /* make the arcs start at the edge of the energy circle */ + if (steps == 0) v[0] = dir*circrad; + else v[0] = v[0] + dir*(steps*outdist); + } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */ + /* make the arcs start at the edge of the energy circle */ + if (steps == 0) v[1] = dir*circrad; + else v[1] = v[1] + dir*(steps*outdist); + } + + v[2] = v[2] - steps*zdist; + + glVertex3fv(v); + + zdist = zdist * mul; + } + + glEnd(); + /* flip the direction */ + dir = -dir; + } + } + } else if(la->type==LA_AREA) { + setlinestyle(3); + if(la->area_shape==LA_AREA_SQUARE) + fdrawbox(-la->area_size*0.5, -la->area_size*0.5, la->area_size*0.5, la->area_size*0.5); + else if(la->area_shape==LA_AREA_RECT) + fdrawbox(-la->area_size*0.5, -la->area_sizey*0.5, la->area_size*0.5, la->area_sizey*0.5); + + glBegin(GL_LINE_STRIP); + glVertex3f(0.0,0.0,-circrad); + glVertex3f(0.0,0.0,-la->dist); + glEnd(); + } + + /* and back to viewspace */ + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + VECCOPY(vec, ob->obmat[3]); + + setlinestyle(0); + + if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) { + drawshadbuflimits(la, ob->obmat); + } + + UI_GetThemeColor4ubv(TH_LAMP, col); + glColor4ub(col[0], col[1], col[2], col[3]); + + glEnable(GL_BLEND); + + if (vec[2]>0) vec[2] -= circrad; + else vec[2] += circrad; + + glBegin(GL_LINE_STRIP); + glVertex3fv(vec); + vec[2]= 0; + glVertex3fv(vec); + glEnd(); + + glPointSize(2.0); + glBegin(GL_POINTS); + glVertex3fv(vec); + glEnd(); + glPointSize(1.0); + + glDisable(GL_BLEND); + + /* restore for drawing extra stuff */ + glColor3fv(curcol); + +} + +static void draw_limit_line(float sta, float end, unsigned int col) +{ + glBegin(GL_LINES); + glVertex3f(0.0, 0.0, -sta); + glVertex3f(0.0, 0.0, -end); + glEnd(); + + glPointSize(3.0); + glBegin(GL_POINTS); + cpack(col); + glVertex3f(0.0, 0.0, -sta); + glVertex3f(0.0, 0.0, -end); + glEnd(); + glPointSize(1.0); +} + + +/* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */ +/* qdn: now also enabled for Blender to set focus point for defocus composit node */ +static void draw_focus_cross(float dist, float size) +{ + glBegin(GL_LINES); + glVertex3f(-size, 0.f, -dist); + glVertex3f(size, 0.f, -dist); + glVertex3f(0.f, -size, -dist); + glVertex3f(0.f, size, -dist); + glEnd(); +} + +/* flag similar to draw_object() */ +static void drawcamera(const bContext *C, Scene *scene, View3D *v3d, Object *ob, int flag) +{ + /* a standing up pyramid with (0,0,0) as top */ + Camera *cam; + World *wrld; + float vec[8][4], tmat[4][4], fac, facx, facy, depth; + int i; + + if(G.f & G_RENDER_SHADOW) + return; + + cam= ob->data; + + glDisable(GL_LIGHTING); + glDisable(GL_CULL_FACE); + + if(v3d->persp>=2 && cam->type==CAM_ORTHO && ob==v3d->camera) { + facx= 0.5*cam->ortho_scale*1.28; + facy= 0.5*cam->ortho_scale*1.024; + depth= -cam->clipsta-0.1; + } + else { + fac= cam->drawsize; + if(v3d->persp>=2 && ob==v3d->camera) fac= cam->clipsta+0.1; /* that way it's always visible */ + + depth= - fac*cam->lens/16.0; + facx= fac*1.28; + facy= fac*1.024; + } + + vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.001; /* GLBUG: for picking at iris Entry (well thats old!) */ + vec[1][0]= facx; vec[1][1]= facy; vec[1][2]= depth; + vec[2][0]= facx; vec[2][1]= -facy; vec[2][2]= depth; + vec[3][0]= -facx; vec[3][1]= -facy; vec[3][2]= depth; + vec[4][0]= -facx; vec[4][1]= facy; vec[4][2]= depth; + + glBegin(GL_LINE_LOOP); + glVertex3fv(vec[1]); + glVertex3fv(vec[2]); + glVertex3fv(vec[3]); + glVertex3fv(vec[4]); + glEnd(); + + + if(v3d->persp>=2 && ob==v3d->camera) return; + + glBegin(GL_LINE_STRIP); + glVertex3fv(vec[2]); + glVertex3fv(vec[0]); + glVertex3fv(vec[1]); + glVertex3fv(vec[4]); + glVertex3fv(vec[0]); + glVertex3fv(vec[3]); + glEnd(); + + + /* arrow on top */ + vec[0][2]= depth; + + + /* draw an outline arrow for inactive cameras and filled + * for active cameras. We actually draw both outline+filled + * for active cameras so the wire can be seen side-on */ + for (i=0;i<2;i++) { + if (i==0) glBegin(GL_LINE_LOOP); + else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES); + else break; + + vec[0][0]= -0.7*cam->drawsize; + vec[0][1]= 1.1*cam->drawsize; + glVertex3fv(vec[0]); + + vec[0][0]= 0.0; + vec[0][1]= 1.8*cam->drawsize; + glVertex3fv(vec[0]); + + vec[0][0]= 0.7*cam->drawsize; + vec[0][1]= 1.1*cam->drawsize; + glVertex3fv(vec[0]); + + glEnd(); + } + + if(flag==0) { + if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) { + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + Mat4CpyMat4(vec, ob->obmat); + Mat4Ortho(vec); + wmMultMatrix(CTX_wm_window(C), vec); + + MTC_Mat4SwapMat4(v3d->persmat, tmat); + wmGetSingleMatrix(CTX_wm_window(C), v3d->persmat); + + if(cam->flag & CAM_SHOWLIMITS) { + draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF); + /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */ + draw_focus_cross(dof_camera(ob), cam->drawsize); + } + + wrld= scene->world; + if(cam->flag & CAM_SHOWMIST) + if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF); + + MTC_Mat4SwapMat4(v3d->persmat, tmat); + } + } +} + +static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel) +{ + BPoint *bp = lt->def; + float *co = dl?dl->verts:NULL; + int u, v, w; + + UI_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + bglBegin(GL_POINTS); + + for(w=0; w<lt->pntsw; w++) { + int wxt = (w==0 || w==lt->pntsw-1); + for(v=0; v<lt->pntsv; v++) { + int vxt = (v==0 || v==lt->pntsv-1); + for(u=0; u<lt->pntsu; u++, bp++, co+=3) { + int uxt = (u==0 || u==lt->pntsu-1); + if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) { + if(bp->hide==0) { + if((bp->f1 & SELECT)==sel) { + bglVertex3fv(dl?co:bp->vec); + } + } + } + } + } + } + + glPointSize(1.0); + bglEnd(); +} + +void lattice_foreachScreenVert(void (*func)(void *userData, BPoint *bp, int x, int y), void *userData) +{ + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + BPoint *bp = editLatt->def; + DispList *dl = find_displist(&G.obedit->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + float pmat[4][4], vmat[4][4]; + int i, N = editLatt->pntsu*editLatt->pntsv*editLatt->pntsw; + short s[2]; + + view3d_get_object_project_mat(v3d, G.obedit, pmat, vmat); + + for (i=0; i<N; i++, bp++, co+=3) { + if (bp->hide==0) { + view3d_project_short_clip(ar, v3d, dl?co:bp->vec, s, pmat, vmat); + func(userData, bp, s[0], s[1]); + } + } +} + +static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol) +{ + int index = ((w*lt->pntsv + v)*lt->pntsu) + u; + + if(use_wcol) { +#if 0 + XXX + float col[3]; + MDeformWeight *mdw= get_defweight (lt->dvert+index, use_wcol-1); + + weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2); + glColor3fv(col); +#endif + } + + if (dl) { + glVertex3fv(&dl->verts[index*3]); + } else { + glVertex3fv(lt->def[index].vec); + } +} + +/* lattice color is hardcoded, now also shows weightgroup values in edit mode */ +static void drawlattice(View3D *v3d, Object *ob) +{ + Lattice *lt; + DispList *dl; + int u, v, w; + int use_wcol= 0; + + lt= (ob==G.obedit)?editLatt:ob->data; + + /* now we default make displist, this will modifiers work for non animated case */ + if(ob->disp.first==NULL) + lattice_calc_modifiers(ob); + dl= find_displist(&ob->disp, DL_VERTS); + + if(ob==G.obedit) { + cpack(0x004000); + + if(ob->defbase.first && lt->dvert) { + use_wcol= ob->actdef; + glShadeModel(GL_SMOOTH); + } + } + + glBegin(GL_LINES); + for(w=0; w<lt->pntsw; w++) { + int wxt = (w==0 || w==lt->pntsw-1); + for(v=0; v<lt->pntsv; v++) { + int vxt = (v==0 || v==lt->pntsv-1); + for(u=0; u<lt->pntsu; u++) { + int uxt = (u==0 || u==lt->pntsu-1); + + if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) { + drawlattice__point(lt, dl, u, v, w-1, use_wcol); + drawlattice__point(lt, dl, u, v, w, use_wcol); + } + if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) { + drawlattice__point(lt, dl, u, v-1, w, use_wcol); + drawlattice__point(lt, dl, u, v, w, use_wcol); + } + if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) { + drawlattice__point(lt, dl, u-1, v, w, use_wcol); + drawlattice__point(lt, dl, u, v, w, use_wcol); + } + } + } + } + glEnd(); + + /* restoration for weight colors */ + if(use_wcol) + glShadeModel(GL_FLAT); + + if(ob==G.obedit) { + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + + lattice_draw_verts(lt, dl, 0); + lattice_draw_verts(lt, dl, 1); + + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + } +} + +/* ***************** ******************** */ + +static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditVert *eve = EM_get_vert_for_index(index); + short s[2]; + + if (eve->h==0) { + if (data->clipVerts) { + view3d_project_short_clip(ar, v3d, co, s, data->pmat, data->vmat); + } else { + view3d_project_short_noclip(ar, co, s, data->pmat); + } + + data->func(data->userData, eve, s[0], s[1], index); + } +} +void mesh_foreachScreenVert(void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts) +{ + struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + View3D *v3d= NULL; // XXX + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + data.func = func; + data.userData = userData; + data.clipVerts = clipVerts; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(1, 0, 0); + dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data); + EM_free_index_arrays(); + + dm->release(dm); +} + +static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co) +{ + struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditEdge *eed = EM_get_edge_for_index(index); + short s[2][2]; + + if (eed->h==0) { + if (data->clipVerts==1) { + view3d_project_short_clip(ar, v3d, v0co, s[0], data->pmat, data->vmat); + view3d_project_short_clip(ar, v3d, v1co, s[1], data->pmat, data->vmat); + } else { + view3d_project_short_noclip(ar, v0co, s[0], data->pmat); + view3d_project_short_noclip(ar, v1co, s[1], data->pmat); + + if (data->clipVerts==2) { + if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<ar->winx && s[0][1]<ar->winy)) + if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<ar->winx && s[1][1]<ar->winy)) + return; + } + } + + data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index); + } +} +void mesh_foreachScreenEdge(void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) +{ + struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + View3D *v3d= NULL; // XXX + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + data.func = func; + data.userData = userData; + data.clipVerts = clipVerts; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(0, 1, 0); + dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data); + EM_free_index_arrays(); + + dm->release(dm); +} + +static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *no) +{ + struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; float pmat[4][4], vmat[4][4]; } *data = userData; + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + EditFace *efa = EM_get_face_for_index(index); + short s[2]; + + if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { + view3d_project_short_clip(ar, v3d, cent, s, data->pmat, data->vmat); + + data->func(data->userData, efa, s[0], s[1], index); + } +} +void mesh_foreachScreenFace(void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData) +{ + struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + View3D *v3d= NULL; // XXX + + data.func = func; + data.userData = userData; + + view3d_get_object_project_mat(v3d, G.obedit, data.pmat, data.vmat); + + EM_init_index_arrays(0, 0, 1); + dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); + EM_free_index_arrays(); + + dm->release(dm); +} + +void nurbs_foreachScreenVert(void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData) +{ + ARegion *ar= NULL; // XXX + View3D *v3d= NULL; // XXX + float pmat[4][4], vmat[4][4]; + short s[2]; + Nurb *nu; + int i; + + view3d_get_object_project_mat(v3d, G.obedit, pmat, vmat); + + for (nu= editNurb.first; nu; nu=nu->next) { + if((nu->type & 7)==CU_BEZIER) { + for (i=0; i<nu->pntsu; i++) { + BezTriple *bezt = &nu->bezt[i]; + + if(bezt->hide==0) { + if (G.f & G_HIDDENHANDLES) { + view3d_project_short_clip(ar, v3d, bezt->vec[1], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 1, s[0], s[1]); + } else { + view3d_project_short_clip(ar, v3d, bezt->vec[0], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 0, s[0], s[1]); + view3d_project_short_clip(ar, v3d, bezt->vec[1], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 1, s[0], s[1]); + view3d_project_short_clip(ar, v3d, bezt->vec[2], s, pmat, vmat); + if (s[0] != IS_CLIPPED) + func(userData, nu, NULL, bezt, 2, s[0], s[1]); + } + } + } + } + else { + for (i=0; i<nu->pntsu*nu->pntsv; i++) { + BPoint *bp = &nu->bp[i]; + + if(bp->hide==0) { + view3d_project_short_clip(ar, v3d, bp->vec, s, pmat, vmat); + func(userData, nu, bp, NULL, -1, s[0], s[1]); + } + } + } + } +} + +/* ************** DRAW MESH ****************** */ + +/* First section is all the "simple" draw routines, + * ones that just pass some sort of primitive to GL, + * with perhaps various options to control lighting, + * color, etc. + * + * These routines should not have user interface related + * logic!!! + */ + +static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no) +{ + Scene *scene= NULL; // XXX + EditFace *efa = EM_get_face_for_index(index); + + if (efa->h==0 && efa->fgonf!=EM_FGON) { + glVertex3fv(cent); + glVertex3f( cent[0] + no[0]*scene->editbutsize, + cent[1] + no[1]*scene->editbutsize, + cent[2] + no[2]*scene->editbutsize); + } +} +static void draw_dm_face_normals(DerivedMesh *dm) { + glBegin(GL_LINES); + dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, 0); + glEnd(); +} + +static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *no) +{ + EditFace *efa = EM_get_face_for_index(index); + int sel = *((int*) userData); + + if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) { + bglVertex3fv(cent); + } +} +static void draw_dm_face_centers(DerivedMesh *dm, int sel) +{ + bglBegin(GL_POINTS); + dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel); + bglEnd(); +} + +static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + Scene *scene= NULL; // XXX + EditVert *eve = EM_get_vert_for_index(index); + + if (eve->h==0) { + glVertex3fv(co); + + if (no_f) { + glVertex3f( co[0] + no_f[0]*scene->editbutsize, + co[1] + no_f[1]*scene->editbutsize, + co[2] + no_f[2]*scene->editbutsize); + } else { + glVertex3f( co[0] + no_s[0]*scene->editbutsize/32767.0f, + co[1] + no_s[1]*scene->editbutsize/32767.0f, + co[2] + no_s[2]*scene->editbutsize/32767.0f); + } + } +} +static void draw_dm_vert_normals(DerivedMesh *dm) { + glBegin(GL_LINES); + dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, NULL); + glEnd(); +} + + /* Draw verts with color set based on selection */ +static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + struct { int sel; EditVert *eve_act; } * data = userData; + EditVert *eve = EM_get_vert_for_index(index); + + if (eve->h==0 && (eve->f&SELECT)==data->sel) { + /* draw active larger - need to stop/start point drawing for this :/ */ + if (eve==data->eve_act) { + float size = UI_GetThemeValuef(TH_VERTEX_SIZE); + UI_ThemeColor4(TH_EDITMESH_ACTIVE); + + bglEnd(); + + glPointSize(size); + bglBegin(GL_POINTS); + bglVertex3fv(co); + bglEnd(); + + UI_ThemeColor4(data->sel?TH_VERTEX_SELECT:TH_VERTEX); + glPointSize(size); + bglBegin(GL_POINTS); + } else { + bglVertex3fv(co); + } + } +} +static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) +{ + struct { int sel; EditVert *eve_act; } data; + data.sel = sel; + data.eve_act = eve_act; + + bglBegin(GL_POINTS); + dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); + bglEnd(); +} + + /* Draw edges with color set based on selection */ +static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) +{ + EditEdge *eed = EM_get_edge_for_index(index); + //unsigned char **cols = userData, *col; + struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData; + unsigned char *col; + + if (eed->h==0) { + if (eed==data->eed_act) { + glColor4ubv(data->actCol); + } else { + if (eed->f&SELECT) { + col = data->selCol; + } else { + col = data->baseCol; + } + /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */ + if (col[3]==0) return 0; + + glColor4ubv(col); + } + return 1; + } else { + return 0; + } +} +static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act) +{ + struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data; + + data.baseCol = baseCol; + data.selCol = selCol; + data.actCol = actCol; + data.eed_act = eed_act; + dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data); +} + + /* Draw edges */ +static int draw_dm_edges__setDrawOptions(void *userData, int index) +{ + return EM_get_edge_for_index(index)->h==0; +} +static void draw_dm_edges(DerivedMesh *dm) +{ + dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL); +} + + /* Draw edges with color interpolated based on selection */ +static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index) +{ + return EM_get_edge_for_index(index)->h==0; +} +static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t) +{ + EditEdge *eed = EM_get_edge_for_index(index); + unsigned char **cols = userData; + unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0]; + unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0]; + + glColor4ub( col0[0] + (col1[0]-col0[0])*t, + col0[1] + (col1[1]-col0[1])*t, + col0[2] + (col1[2]-col0[2])*t, + col0[3] + (col1[3]-col0[3])*t); +} +static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) +{ + unsigned char *cols[2]; + cols[0] = baseCol; + cols[1] = selCol; + dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols); +} + + /* Draw only seam edges */ +static int draw_dm_edges_seams__setDrawOptions(void *userData, int index) +{ + EditEdge *eed = EM_get_edge_for_index(index); + + return (eed->h==0 && eed->seam); +} +static void draw_dm_edges_seams(DerivedMesh *dm) +{ + dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL); +} + + /* Draw only sharp edges */ +static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index) +{ + EditEdge *eed = EM_get_edge_for_index(index); + + return (eed->h==0 && eed->sharp); +} +static void draw_dm_edges_sharp(DerivedMesh *dm) +{ + dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL); +} + + + /* Draw faces with color set based on selection + * return 2 for the active face so it renders with stipple enabled */ +static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r) +{ + struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData; + EditFace *efa = EM_get_face_for_index(index); + unsigned char *col; + + if (efa->h==0) { + if (efa == data->efa_act) { + glColor4ubv(data->cols[2]); + return 2; /* stipple */ + } else { + col = data->cols[(efa->f&SELECT)?1:0]; + if (col[3]==0) return 0; + glColor4ubv(col); + return 1; + } + } + return 0; +} + +/* also draws the active face */ +static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) +{ + struct { unsigned char *cols[3]; EditFace *efa_act; } data; + data.cols[0] = baseCol; + data.cols[1] = selCol; + data.cols[2] = actCol; + data.efa_act = efa_act; + + dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0); +} + +static int draw_dm_creases__setDrawOptions(void *userData, int index) +{ + EditEdge *eed = EM_get_edge_for_index(index); + + if (eed->h==0 && eed->crease!=0.0) { + UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->crease); + return 1; + } else { + return 0; + } +} +static void draw_dm_creases(DerivedMesh *dm) +{ + glLineWidth(3.0); + dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL); + glLineWidth(1.0); +} + +static int draw_dm_bweights__setDrawOptions(void *userData, int index) +{ + EditEdge *eed = EM_get_edge_for_index(index); + + if (eed->h==0 && eed->bweight!=0.0) { + UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight); + return 1; + } else { + return 0; + } +} +static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + EditVert *eve = EM_get_vert_for_index(index); + + if (eve->h==0 && eve->bweight!=0.0) { + UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight); + bglVertex3fv(co); + } +} +static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) +{ + if (scene->selectmode & SCE_SELECT_VERTEX) { + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); + bglBegin(GL_POINTS); + dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL); + bglEnd(); + } + else { + glLineWidth(3.0); + dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL); + glLineWidth(1.0); + } +} + +/* Second section of routines: Combine first sets to form fancy + * drawing routines (for example rendering twice to get overlays). + * + * Also includes routines that are basic drawing but are too + * specialized to be split out (like drawing creases or measurements). + */ + +/* EditMesh drawing routines*/ + +static void draw_em_fancy_verts(Scene *scene, View3D *v3d, EditMesh *em, DerivedMesh *cageDM, EditVert *eve_act) +{ + int sel; + + if(v3d->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select + + for (sel=0; sel<2; sel++) { + char col[4], fcol[4]; + int pass; + + UI_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col); + UI_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol); + + for (pass=0; pass<2; pass++) { + float size = UI_GetThemeValuef(TH_VERTEX_SIZE); + float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); + + if (pass==0) { + if(v3d->zbuf && !(v3d->flag&V3D_ZBUF_SELECT)) { + glDisable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + } else { + continue; + } + + size = (size>2.1?size/2.0:size); + fsize = (fsize>2.1?fsize/2.0:fsize); + col[3] = fcol[3] = 100; + } else { + col[3] = fcol[3] = 255; + } + + if(scene->selectmode & SCE_SELECT_VERTEX) { + glPointSize(size); + glColor4ubv((GLubyte *)col); + draw_dm_verts(cageDM, sel, eve_act); + } + + if( CHECK_OB_DRAWFACEDOT(scene, v3d, G.obedit->dt) ) { + glPointSize(fsize); + glColor4ubv((GLubyte *)fcol); + draw_dm_face_centers(cageDM, sel); + } + + if (pass==0) { + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + } + } + } + + if(v3d->zbuf) glDepthMask(1); + glPointSize(1.0); +} + +static void draw_em_fancy_edges(Scene *scene, View3D *v3d, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act) +{ + int pass; + unsigned char wireCol[4], selCol[4], actCol[4]; + + /* since this function does transparant... */ + UI_GetThemeColor4ubv(TH_EDGE_SELECT, (char *)selCol); + UI_GetThemeColor4ubv(TH_WIRE, (char *)wireCol); + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)actCol); + + /* when sel only is used, dont render wire, only selected, this is used for + * textured draw mode when the 'edges' option is disabled */ + if (sel_only) + wireCol[3] = 0; + + for (pass=0; pass<2; pass++) { + /* show wires in transparant when no zbuf clipping for select */ + if (pass==0) { + if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) { + glEnable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + selCol[3] = 85; + if (!sel_only) wireCol[3] = 85; + } else { + continue; + } + } else { + selCol[3] = 255; + if (!sel_only) wireCol[3] = 255; + } + + if(scene->selectmode == SCE_SELECT_FACE) { + draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + } + else if( (G.f & G_DRAWEDGES) || (scene->selectmode & SCE_SELECT_EDGE) ) { + if(cageDM->drawMappedEdgesInterp && (scene->selectmode & SCE_SELECT_VERTEX)) { + glShadeModel(GL_SMOOTH); + draw_dm_edges_sel_interp(cageDM, wireCol, selCol); + glShadeModel(GL_FLAT); + } else { + draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + } + } + else { + if (!sel_only) { + glColor4ubv(wireCol); + draw_dm_edges(cageDM); + } + } + + if (pass==0) { + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + } + } +} + +static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em) +{ + EditEdge *eed; + EditFace *efa; + float v1[3], v2[3], v3[3], v4[3]; + float fvec[3]; + char val[32]; /* Stores the measurement display text here */ + char conv_float[5]; /* Use a float conversion matching the grid size */ + float area, col[3]; /* area of the face, color of the text to draw */ + + if(G.f & (G_RENDER_OGL|G_RENDER_SHADOW)) + return; + + /* make the precission of the pronted value proportionate to the gridsize */ + if ((v3d->grid) < 0.01) + strcpy(conv_float, "%.6f"); + else if ((v3d->grid) < 0.1) + strcpy(conv_float, "%.5f"); + else if ((v3d->grid) < 1.0) + strcpy(conv_float, "%.4f"); + else if ((v3d->grid) < 10.0) + strcpy(conv_float, "%.3f"); + else + strcpy(conv_float, "%.2f"); + + + if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0) + glDisable(GL_DEPTH_TEST); + + if(v3d->zbuf) bglPolygonOffset(5.0); + + if(G.f & G_DRAW_EDGELEN) { + UI_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more red */ + if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;} + else col[0]= col[0]*0.7 + 0.3; + glColor3fv(col); + + for(eed= em->edges.first; eed; eed= eed->next) { + /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */ + if((eed->h != EM_FGON) && ((eed->f & SELECT) || (G.moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) { + VECCOPY(v1, eed->v1->co); + VECCOPY(v2, eed->v2->co); + + glRasterPos3f( 0.5*(v1[0]+v2[0]), 0.5*(v1[1]+v2[1]), 0.5*(v1[2]+v2[2])); + + if(v3d->flag & V3D_GLOBAL_STATS) { + Mat4MulVecfl(ob->obmat, v1); + Mat4MulVecfl(ob->obmat, v2); + } + + sprintf(val, conv_float, VecLenf(v1, v2)); + BMF_DrawString( G.fonts, val); + } + } + } + + if(G.f & G_DRAW_FACEAREA) { +// XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now? + + UI_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more green */ + if(col[1]> 0.5) {col[0]*=0.7; col[2]*= 0.7;} + else col[1]= col[1]*0.7 + 0.3; + glColor3fv(col); + + for(efa= em->faces.first; efa; efa= efa->next) { + if((efa->f & SELECT)) { // XXX || (G.moving && faceselectedOR(efa, SELECT)) ) { + VECCOPY(v1, efa->v1->co); + VECCOPY(v2, efa->v2->co); + VECCOPY(v3, efa->v3->co); + if (efa->v4) { + VECCOPY(v4, efa->v4->co); + } + if(v3d->flag & V3D_GLOBAL_STATS) { + Mat4MulVecfl(ob->obmat, v1); + Mat4MulVecfl(ob->obmat, v2); + Mat4MulVecfl(ob->obmat, v3); + if (efa->v4) Mat4MulVecfl(ob->obmat, v4); + } + + if (efa->v4) + area= AreaQ3Dfl(v1, v2, v3, v4); + else + area = AreaT3Dfl(v1, v2, v3); + + sprintf(val, conv_float, area); + glRasterPos3fv(efa->cent); + BMF_DrawString( G.fonts, val); + } + } + } + + if(G.f & G_DRAW_EDGEANG) { + EditEdge *e1, *e2, *e3, *e4; + + UI_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more blue */ + if(col[2]> 0.5) {col[0]*=0.7; col[1]*= 0.7;} + else col[2]= col[2]*0.7 + 0.3; + glColor3fv(col); + + for(efa= em->faces.first; efa; efa= efa->next) { + VECCOPY(v1, efa->v1->co); + VECCOPY(v2, efa->v2->co); + VECCOPY(v3, efa->v3->co); + if(efa->v4) { + VECCOPY(v4, efa->v4->co); + } + else { + VECCOPY(v4, v3); + } + if(v3d->flag & V3D_GLOBAL_STATS) { + Mat4MulVecfl(ob->obmat, v1); + Mat4MulVecfl(ob->obmat, v2); + Mat4MulVecfl(ob->obmat, v3); + Mat4MulVecfl(ob->obmat, v4); + } + + e1= efa->e1; + e2= efa->e2; + e3= efa->e3; + if(efa->e4) e4= efa->e4; else e4= e3; + + /* Calculate the angles */ + + if( (e4->f & e1->f & SELECT) || (G.moving && (efa->v1->f & SELECT)) ) { + /* Vec 1 */ + sprintf(val,"%.3f", VecAngle3(v4, v1, v2)); + VecLerpf(fvec, efa->cent, efa->v1->co, 0.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) { + /* Vec 2 */ + sprintf(val,"%.3f", VecAngle3(v1, v2, v3)); + VecLerpf(fvec, efa->cent, efa->v2->co, 0.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) { + /* Vec 3 */ + if(efa->v4) + sprintf(val,"%.3f", VecAngle3(v2, v3, v4)); + else + sprintf(val,"%.3f", VecAngle3(v2, v3, v1)); + VecLerpf(fvec, efa->cent, efa->v3->co, 0.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + /* Vec 4 */ + if(efa->v4) { + if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) { + sprintf(val,"%.3f", VecAngle3(v3, v4, v1)); + VecLerpf(fvec, efa->cent, efa->v4->co, 0.8); + glRasterPos3fv(fvec); + BMF_DrawString( G.fonts, val); + } + } + } + } + + if(v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + bglPolygonOffset(0.0); + } +} + +static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth_r) +{ + EditFace *efa = EM_get_face_for_index(index); + + if (efa->h==0) { + GPU_enable_material(efa->mat_nr+1, NULL); + return 1; + } + else + return 0; +} + +static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index) +{ + EditFace *efa = EM_get_face_for_index(index); + + return (efa->h==0); +} + +static void draw_em_fancy(Scene *scene, View3D *v3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) +{ + Mesh *me = ob->data; + EditFace *efa_act = EM_get_actFace(0); /* annoying but active faces is stored differently */ + EditEdge *eed_act = NULL; + EditVert *eve_act = NULL; + + if (G.editMesh->selected.last) { + EditSelection *ese = G.editMesh->selected.last; + /* face is handeled above */ + /*if (ese->type == EDITFACE ) { + efa_act = (EditFace *)ese->data; + } else */ if ( ese->type == EDITEDGE ) { + eed_act = (EditEdge *)ese->data; + } else if ( ese->type == EDITVERT ) { + eve_act = (EditVert *)ese->data; + } + } + + EM_init_index_arrays(1, 1, 1); + + if(dt>OB_WIRE) { + if(CHECK_OB_DRAWTEXTURE(v3d, dt)) { + if(draw_glsl_material(scene, ob, v3d, dt)) { + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + + finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material, + draw_em_fancy__setGLSLFaceOpts, NULL); + GPU_disable_material(); + + glFrontFace(GL_CCW); + } + else { + draw_mesh_textured(scene, v3d, ob, finalDM, 0); + } + } + else { + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED); + + glEnable(GL_LIGHTING); + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0); + + glFrontFace(GL_CCW); + glDisable(GL_LIGHTING); + } + + // Setup for drawing wire over, disable zbuffer + // write to show selected edge wires better + UI_ThemeColor(TH_WIRE); + + bglPolygonOffset(1.0); + glDepthMask(0); + } + else { + if (cageDM!=finalDM) { + UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); + finalDM->drawEdges(finalDM, 1); + } + } + + if((G.f & (G_DRAWFACES)) || FACESEL_PAINT_TEST) { /* transp faces */ + unsigned char col1[4], col2[4], col3[4]; + + UI_GetThemeColor4ubv(TH_FACE, (char *)col1); + UI_GetThemeColor4ubv(TH_FACE_SELECT, (char *)col2); + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3); + + glEnable(GL_BLEND); + glDepthMask(0); // disable write in zbuffer, needed for nice transp + + /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */ + if CHECK_OB_DRAWTEXTURE(v3d, dt) + col1[3] = 0; + + draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + + glDisable(GL_BLEND); + glDepthMask(1); // restore write in zbuffer + } else if (efa_act) { + /* even if draw faces is off it would be nice to draw the stipple face + * Make all other faces zero alpha except for the active + * */ + unsigned char col1[4], col2[4], col3[4]; + col1[3] = col2[3] = 0; /* dont draw */ + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3); + + glEnable(GL_BLEND); + glDepthMask(0); // disable write in zbuffer, needed for nice transp + + draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + + glDisable(GL_BLEND); + glDepthMask(1); // restore write in zbuffer + + } + + /* here starts all fancy draw-extra over */ + if((G.f & G_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(v3d, dt)) { + /* we are drawing textures and 'G_DRAWEDGES' is disabled, dont draw any edges */ + + /* only draw selected edges otherwise there is no way of telling if a face is selected */ + draw_em_fancy_edges(scene, v3d, cageDM, 1, eed_act); + + } else { + if(G.f & G_DRAWSEAMS) { + UI_ThemeColor(TH_EDGE_SEAM); + glLineWidth(2); + + draw_dm_edges_seams(cageDM); + + glColor3ub(0,0,0); + glLineWidth(1); + } + + if(G.f & G_DRAWSHARP) { + UI_ThemeColor(TH_EDGE_SHARP); + glLineWidth(2); + + draw_dm_edges_sharp(cageDM); + + glColor3ub(0,0,0); + glLineWidth(1); + } + + if(G.f & G_DRAWCREASES) { + draw_dm_creases(cageDM); + } + if(G.f & G_DRAWBWEIGHTS) { + draw_dm_bweights(scene, cageDM); + } + + draw_em_fancy_edges(scene, v3d, cageDM, 0, eed_act); + } + if(ob==G.obedit) { +// XXX retopo_matrix_update(v3d); + + draw_em_fancy_verts(scene, v3d, em, cageDM, eve_act); + + if(G.f & G_DRAWNORMALS) { + UI_ThemeColor(TH_NORMAL); + draw_dm_face_normals(cageDM); + } + if(G.f & G_DRAW_VNORMALS) { + UI_ThemeColor(TH_NORMAL); + draw_dm_vert_normals(cageDM); + } + + if(G.f & (G_DRAW_EDGELEN|G_DRAW_FACEAREA|G_DRAW_EDGEANG)) + draw_em_measure_stats(v3d, ob, em); + } + + if(dt>OB_WIRE) { + glDepthMask(1); + bglPolygonOffset(0.0); + GPU_disable_material(); + } + + EM_free_index_arrays(); +} + +/* Mesh drawing routines */ + +static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) +{ + + if(v3d->transp==0) { // not when we draw the transparent pass + glLineWidth(2.0); + glDepthMask(0); + + /* if transparent, we cannot draw the edges for solid select... edges have no material info. + drawFacesSolid() doesn't draw the transparent faces */ + if(ob->dtx & OB_DRAWTRANSP) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + dm->drawFacesSolid(dm, GPU_enable_material); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + GPU_disable_material(); + } + else { + dm->drawEdges(dm, 0); + } + + glLineWidth(1.0); + glDepthMask(1); + } +} + +static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) +{ + *drawSmooth_r = 1; + return 1; +} + +static void draw_mesh_fancy(Scene *scene, View3D *v3d, Base *base, int dt, int flag) +{ + Object *ob= base->object; + Mesh *me = ob->data; + Material *ma= give_current_material(ob, 1); + int hasHaloMat = (ma && (ma->mode&MA_HALO)); + int draw_wire = 0; + int totvert, totedge, totface; + DispList *dl; + DerivedMesh *dm= mesh_get_derived_final(ob, get_viewedit_datamask()); + + if(!dm) + return; + + if (ob->dtx&OB_DRAWWIRE) { + draw_wire = 2; /* draw wire after solid using zoffset and depth buffer adjusment */ + } + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm); + + /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ + if(dt!=OB_SHADED) + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + + // Unwanted combination. + if (ob==OBACT && FACESEL_PAINT_TEST) draw_wire = 0; + + if(dt==OB_BOUNDBOX) { + draw_bounding_volume(ob); + } + else if(hasHaloMat || (totface==0 && totedge==0)) { + glPointSize(1.5); + dm->drawVerts(dm); + glPointSize(1.0); + } + else if(dt==OB_WIRE || totface==0) { + draw_wire = 1; /* draw wire only, no depth buffer stuff */ + } + else if( (ob==OBACT && (G.f & G_TEXTUREPAINT || FACESEL_PAINT_TEST)) || + CHECK_OB_DRAWTEXTURE(v3d, dt)) + { + int faceselect= (ob==OBACT && FACESEL_PAINT_TEST); + + if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || FACESEL_PAINT_TEST) && !draw_wire) { + draw_mesh_object_outline(v3d, ob, dm); + } + + if(draw_glsl_material(scene, ob, v3d, dt)) { + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + + dm->drawFacesGLSL(dm, GPU_enable_material); +// if(get_ob_property(ob, "Text")) +// XXX draw_mesh_text(ob, 1); + GPU_disable_material(); + + glFrontFace(GL_CCW); + } + else { + draw_mesh_textured(scene, v3d, ob, dm, faceselect); + } + + if(!faceselect) { + if(base->flag & SELECT) + UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); + else + UI_ThemeColor(TH_WIRE); + + dm->drawLooseEdges(dm); + } + } + else if(dt==OB_SOLID) { + if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) + draw_mesh_object_outline(v3d, ob, dm); + + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED ); + + glEnable(GL_LIGHTING); + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + + dm->drawFacesSolid(dm, GPU_enable_material); + GPU_disable_material(); + + glFrontFace(GL_CCW); + glDisable(GL_LIGHTING); + + if(base->flag & SELECT) { + UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); + } else { + UI_ThemeColor(TH_WIRE); + } + dm->drawLooseEdges(dm); + } + else if(dt==OB_SHADED) { + int do_draw= 1; /* to resolve all G.f settings below... */ + + if(ob==OBACT) { + do_draw= 0; + if( (G.f & G_WEIGHTPAINT)) { + /* enforce default material settings */ + GPU_enable_material(0, NULL); + + /* but set default spec */ + glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); + glEnable(GL_COLOR_MATERIAL); /* according manpages needed */ + glColor3ub(120, 120, 120); + glDisable(GL_COLOR_MATERIAL); + /* diffuse */ + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHTING); + + GPU_disable_material(); + } + else if((G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) && me->mcol) { + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1); + } + else if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) { + glColor3f(1.0f, 1.0f, 1.0f); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0); + } + else do_draw= 1; + } + if(do_draw) { + dl = ob->disp.first; + if (!dl || !dl->col1) { + /* release and reload derivedmesh because it might be freed in + shadeDispList due to a different datamask */ + dm->release(dm); + shadeDispList(base); + dl = find_displist(&ob->disp, DL_VERTCOL); + dm= mesh_get_derived_final(ob, get_viewedit_datamask()); + } + + if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) { + draw_mesh_object_outline(v3d, ob, dm); + } + + /* False for dupliframe objects */ + if (dl) { + unsigned int *obCol1 = dl->col1; + unsigned int *obCol2 = dl->col2; + + dm->drawFacesColored(dm, me->flag&ME_TWOSIDED, (unsigned char*) obCol1, (unsigned char*) obCol2); + } + + if(base->flag & SELECT) { + UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); + } else { + UI_ThemeColor(TH_WIRE); + } + dm->drawLooseEdges(dm); + } + } + + /* set default draw color back for wire or for draw-extra later on */ + if (dt!=OB_WIRE) { + if(base->flag & SELECT) { + if(ob==OBACT && ob->flag & OB_FROMGROUP) + UI_ThemeColor(TH_GROUP_ACTIVE); + else if(ob->flag & OB_FROMGROUP) + UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); + else if(flag!=DRAW_CONSTCOLOR) + UI_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT); + else + glColor3ub(80,80,80); + } else { + if (ob->flag & OB_FROMGROUP) + UI_ThemeColor(TH_GROUP); + else { + if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR) + glColor3ub(80,80,80); + else + UI_ThemeColor(TH_WIRE); + } + } + } + if (draw_wire) { + /* If drawing wire and drawtype is not OB_WIRE then we are + * overlaying the wires. + * + * UPDATE bug #10290 - With this wire-only objects can draw + * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059 + * + * if draw wire is 1 then just drawing wire, no need for depth buffer stuff, + * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks. + */ + if (dt!=OB_WIRE && draw_wire==2) { + bglPolygonOffset(1.0); + glDepthMask(0); // disable write in zbuffer, selected edge wires show better + } + + dm->drawEdges(dm, (dt==OB_WIRE || totface==0)); + + if (dt!=OB_WIRE && draw_wire==2) { + glDepthMask(1); + bglPolygonOffset(0.0); + } + } + + dm->release(dm); +} + +/* returns 1 if nothing was drawn, for detecting to draw an object center */ +static int draw_mesh_object(Scene *scene, View3D *v3d, Base *base, int dt, int flag) +{ + Object *ob= base->object; + Mesh *me= ob->data; + int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha; + + if(G.obedit && ob!=G.obedit && ob->data==G.obedit->data) { + if(ob_get_key(ob)); + else drawlinked= 1; + } + + if(ob==G.obedit || drawlinked) { + DerivedMesh *finalDM, *cageDM; + + if (G.obedit!=ob) + finalDM = cageDM = editmesh_get_derived_base(); + else + cageDM = editmesh_get_derived_cage_and_final(&finalDM, + get_viewedit_datamask()); + + if(dt>OB_WIRE) { + // no transp in editmode, the fancy draw over goes bad then + glsl = draw_glsl_material(scene, ob, v3d, dt); + GPU_set_object_materials(scene, ob, glsl, NULL); + } + + draw_em_fancy(scene, v3d, ob, G.editMesh, cageDM, finalDM, dt); + + if (G.obedit!=ob && finalDM) + finalDM->release(finalDM); + } +// else if(!G.obedit && (G.f & G_SCULPTMODE) &&(scene->sculptdata.flags & SCULPT_DRAW_FAST) && +// OBACT==ob && !sculpt_modifiers_active(ob)) { +// XXX sculptmode_draw_mesh(0); +// } + else { + /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */ + if(me->totface<=4 || boundbox_clip(v3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) { + glsl = draw_glsl_material(scene, ob, v3d, dt); + check_alpha = check_material_alpha(base, ob, glsl); + + if(dt==OB_SOLID || glsl) { + GPU_set_object_materials(scene, ob, glsl, + (check_alpha)? &do_alpha_pass: NULL); + } + + draw_mesh_fancy(scene, v3d, base, dt, flag); + + if(me->totvert==0) retval= 1; + } + } + + /* GPU_set_object_materials checked if this is needed */ + if(do_alpha_pass) add_view3d_after(v3d, base, V3D_TRANSP, flag); + + return retval; +} + +/* ************** DRAW DISPLIST ****************** */ + +static int draw_index_wire= 1; +static int index3_nors_incr= 1; + +/* returns 1 when nothing was drawn */ +static int drawDispListwire(ListBase *dlbase) +{ + DispList *dl; + int parts, nr; + float *data; + + if(dlbase==NULL) return 1; + + glDisableClientState(GL_NORMAL_ARRAY); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + for(dl= dlbase->first; dl; dl= dl->next) { + if(dl->parts==0 || dl->nr==0) + continue; + + data= dl->verts; + + switch(dl->type) { + case DL_SEGM: + + glVertexPointer(3, GL_FLOAT, 0, data); + + for(parts=0; parts<dl->parts; parts++) + glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr); + + break; + case DL_POLY: + + glVertexPointer(3, GL_FLOAT, 0, data); + + for(parts=0; parts<dl->parts; parts++) + glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr); + + break; + case DL_SURF: + + glVertexPointer(3, GL_FLOAT, 0, data); + + for(parts=0; parts<dl->parts; parts++) { + if(dl->flag & DL_CYCL_U) + glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr); + else + glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr); + } + + for(nr=0; nr<dl->nr; nr++) { + int ofs= 3*dl->nr; + + data= ( dl->verts )+3*nr; + parts= dl->parts; + + if(dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP); + else glBegin(GL_LINE_STRIP); + + while(parts--) { + glVertex3fv(data); + data+=ofs; + } + glEnd(); + + /* (ton) this code crashes for me when resolv is 86 or higher... no clue */ +// glVertexPointer(3, GL_FLOAT, sizeof(float)*3*dl->nr, data + 3*nr); +// if(dl->flag & DL_CYCL_V) +// glDrawArrays(GL_LINE_LOOP, 0, dl->parts); +// else +// glDrawArrays(GL_LINE_STRIP, 0, dl->parts); + } + break; + + case DL_INDEX3: + if(draw_index_wire) { + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); + } + break; + + case DL_INDEX4: + if(draw_index_wire) { + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); + } + break; + } + } + + glEnableClientState(GL_NORMAL_ARRAY); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + return 0; +} + +static void drawDispListsolid(ListBase *lb, Object *ob, int glsl) +{ + DispList *dl; + GPUVertexAttribs gattribs; + float *data, curcol[4]; + float *ndata; + + if(lb==NULL) return; + + /* for drawing wire */ + glGetFloatv(GL_CURRENT_COLOR, curcol); + + glEnable(GL_LIGHTING); + + if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); + else glFrontFace(GL_CCW); + + if(ob->type==OB_MBALL) { // mball always smooth shaded + glShadeModel(GL_SMOOTH); + } + + dl= lb->first; + while(dl) { + data= dl->verts; + ndata= dl->nors; + + switch(dl->type) { + case DL_SEGM: + if(ob->type==OB_SURF) { + int nr; + + glDisable(GL_LIGHTING); + glColor3fv(curcol); + + // glVertexPointer(3, GL_FLOAT, 0, dl->verts); + // glDrawArrays(GL_LINE_STRIP, 0, dl->nr); + + glBegin(GL_LINE_STRIP); + for(nr= dl->nr; nr; nr--, data+=3) + glVertex3fv(data); + glEnd(); + + glEnable(GL_LIGHTING); + } + break; + case DL_POLY: + if(ob->type==OB_SURF) { + int nr; + + UI_ThemeColor(TH_WIRE); + glDisable(GL_LIGHTING); + + /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */ + //glVertexPointer(3, GL_FLOAT, 0, dl->verts); + //glDrawArrays(GL_LINE_LOOP, 0, dl->nr); + + glBegin(GL_LINE_LOOP); + for(nr= dl->nr; nr; nr--, data+=3) + glVertex3fv(data); + glEnd(); + + glEnable(GL_LIGHTING); + break; + } + case DL_SURF: + + if(dl->index) { + GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); + + if(dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH); + else glShadeModel(GL_FLAT); + + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glNormalPointer(GL_FLOAT, 0, dl->nors); + glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index); + GPU_disable_material(); + } + break; + + case DL_INDEX3: + GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); + + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + + /* voor polys only one normal needed */ + if(index3_nors_incr==0) { + glDisableClientState(GL_NORMAL_ARRAY); + glNormal3fv(ndata); + } + else + glNormalPointer(GL_FLOAT, 0, dl->nors); + + glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); + GPU_disable_material(); + + if(index3_nors_incr==0) + glEnableClientState(GL_NORMAL_ARRAY); + + break; + + case DL_INDEX4: + GPU_enable_material(dl->col+1, (glsl)? &gattribs: NULL); + + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glNormalPointer(GL_FLOAT, 0, dl->nors); + glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); + + GPU_disable_material(); + + break; + } + dl= dl->next; + } + + glShadeModel(GL_FLAT); + glDisable(GL_LIGHTING); + glFrontFace(GL_CCW); +} + +static void drawDispListshaded(ListBase *lb, Object *ob) +{ + DispList *dl, *dlob; + unsigned int *cdata; + + if(lb==NULL) return; + + glShadeModel(GL_SMOOTH); + glDisableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + dl= lb->first; + dlob= ob->disp.first; + while(dl && dlob) { + + cdata= dlob->col1; + if(cdata==NULL) break; + + switch(dl->type) { + case DL_SURF: + if(dl->index) { + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); + glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index); + } + break; + + case DL_INDEX3: + + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); + glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index); + break; + + case DL_INDEX4: + + glVertexPointer(3, GL_FLOAT, 0, dl->verts); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata); + glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index); + break; + } + + dl= dl->next; + dlob= dlob->next; + } + + glShadeModel(GL_FLAT); + glEnableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); +} + +/* returns 1 when nothing was drawn */ +static int drawDispList(Scene *scene, View3D *v3d, Base *base, int dt) +{ + Object *ob= base->object; + ListBase *lb=0; + DispList *dl; + Curve *cu; + int solid, retval= 0; + + solid= (dt > OB_WIRE); + + switch(ob->type) { + case OB_FONT: + case OB_CURVE: + cu= ob->data; + + lb= &cu->disp; + + if(solid) { + dl= lb->first; + if(dl==NULL) return 1; + + if(dl->nors==0) addnormalsDispList(ob, lb); + index3_nors_incr= 0; + + if( displist_has_faces(lb)==0) { + draw_index_wire= 0; + drawDispListwire(lb); + draw_index_wire= 1; + } + else { + if(draw_glsl_material(scene, ob, v3d, dt)) { + GPU_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt == OB_SHADED) { + if(ob->disp.first==0) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + drawDispListsolid(lb, ob, 0); + } + if(ob==G.obedit && cu->bevobj==NULL && cu->taperobj==NULL && cu->ext1 == 0.0 && cu->ext2 == 0.0) { + cpack(0); + draw_index_wire= 0; + drawDispListwire(lb); + draw_index_wire= 1; + } + } + index3_nors_incr= 1; + } + else { + draw_index_wire= 0; + retval= drawDispListwire(lb); + draw_index_wire= 1; + } + break; + case OB_SURF: + + lb= &((Curve *)ob->data)->disp; + + if(solid) { + dl= lb->first; + if(dl==NULL) return 1; + + if(dl->nors==NULL) addnormalsDispList(ob, lb); + + if(draw_glsl_material(scene, ob, v3d, dt)) { + GPU_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt==OB_SHADED) { + if(ob->disp.first==NULL) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + + drawDispListsolid(lb, ob, 0); + } + } + else { + retval= drawDispListwire(lb); + } + break; + case OB_MBALL: + + if( is_basis_mball(ob)) { + lb= &ob->disp; + if(lb->first==NULL) makeDispListMBall(ob); + if(lb->first==NULL) return 1; + + if(solid) { + + if(draw_glsl_material(scene, ob, v3d, dt)) { + GPU_set_object_materials(scene, ob, 1, NULL); + drawDispListsolid(lb, ob, 1); + } + else if(dt == OB_SHADED) { + dl= lb->first; + if(dl && dl->col1==0) shadeDispList(base); + drawDispListshaded(lb, ob); + } + else { + GPU_set_object_materials(scene, ob, 0, NULL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + + drawDispListsolid(lb, ob, 0); + } + } + else{ + /* MetaBalls use DL_INDEX4 type of DispList */ + retval= drawDispListwire(lb); + } + } + break; + } + + return retval; +} + +/* unified drawing of all new particle systems draw types except dupli ob & group */ +/* mostly tries to use vertex arrays for speed */ + +/* 1. check that everything is ok & updated */ +/* 2. start initialising things */ +/* 3. initialize according to draw type */ +/* 4. allocate drawing data arrays */ +/* 5. start filling the arrays */ +/* 6. draw the arrays */ +/* 7. clean up */ +static void draw_new_particle_system(const bContext *C, View3D *v3d, Base *base, ParticleSystem *psys, int dt) +{ + Object *ob=base->object; + ParticleSystemModifierData *psmd; + ParticleSettings *part; + ParticleData *pars, *pa; + ParticleKey state, *states=0; + ParticleCacheKey *cache=0; + Material *ma; + Object *bb_ob=0; + float vel[3], vec[3], vec2[3], imat[4][4], onevec[3]={0.0f,0.0f,0.0f}, bb_center[3]; + float timestep, pixsize=1.0, pa_size, pa_time, r_tilt; + float cfra=bsystem_time(ob,(float)CFRA,0.0); + float *vdata=0, *vedata=0, *cdata=0, *ndata=0, *vd=0, *ved=0, *cd=0, *nd=0, xvec[3], yvec[3], zvec[3]; + float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f; + int a, k, k_max=0, totpart, totpoint=0, draw_as, path_nbr=0; + int path_possible=0, keys_possible=0, draw_keys=0, totchild=0; + int select=ob->flag&SELECT, create_cdata=0; + GLint polygonmode[2]; + char val[32]; + +/* 1. */ + if(psys==0) + return; + + part=psys->part; + pars=psys->particles; + + if(part==0 || !psys_check_enabled(ob, psys)) + return; + + if(pars==0) return; + + if(!G.obedit && psys_in_edit_mode(psys) + && psys->flag & PSYS_HAIR_DONE && part->draw_as==PART_DRAW_PATH) + return; + + if(part->draw_as==PART_DRAW_NOT) return; + +/* 2. */ + if(part->phystype==PART_PHYS_KEYED){ + if(psys->flag & PSYS_FIRST_KEYED){ + if(psys->flag&PSYS_KEYED){ + select=psys_count_keyed_targets(ob,psys); + if(psys->totkeyed==0) + return; + } + } + else + return; + } + + if(select){ + select=0; + if(psys_get_current(ob)==psys) + select=1; + } + + psys->flag|=PSYS_DRAWING; + + if(part->type==PART_HAIR && !psys->childcache) + totchild=0; + else + totchild=psys->totchild*part->disp/100; + + ma= give_current_material(ob,part->omat); + + if(ma) { + ma_r = ma->r; + ma_g = ma->g; + ma_b = ma->b; + } + + if(v3d->zbuf) glDepthMask(1); + + if(select) + cpack(0xFFFFFF); + else if((ma) && (part->draw&PART_DRAW_MAT_COL)) { + glColor3f(ma->r,ma->g,ma->b); + create_cdata = 1; + } + else + cpack(0); + + psmd= psys_get_modifier(ob,psys); + + timestep= psys_get_timestep(part); + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) { + float mat[4][4]; + Mat4MulMat4(mat, psys->imat, ob->obmat); + wmMultMatrix(CTX_wm_window(C), mat); + } + + totpart=psys->totpart; + draw_as=part->draw_as; + + if(part->flag&PART_GLOB_TIME) + cfra=bsystem_time(0,(float)CFRA,0.0); + + if(psys->pathcache){ + path_possible=1; + keys_possible=1; + } + if(draw_as==PART_DRAW_PATH && path_possible==0) + draw_as=PART_DRAW_DOT; + + if(draw_as!=PART_DRAW_PATH && keys_possible && part->draw&PART_DRAW_KEYS){ + path_nbr=part->keys_step; + draw_keys=1; + } + +/* 3. */ + switch(draw_as){ + case PART_DRAW_DOT: + if(part->draw_size) + glPointSize(part->draw_size); + else + glPointSize(2.0); /* default dot size */ + break; + case PART_DRAW_CIRC: + /* calculate view aligned matrix: */ + Mat4CpyMat4(imat, v3d->viewinv); + Normalize(imat[0]); + Normalize(imat[1]); + /* no break! */ + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + /* lets calculate the scale: */ + pixsize= v3d->persmat[0][3]*ob->obmat[3][0]+ v3d->persmat[1][3]*ob->obmat[3][1]+ v3d->persmat[2][3]*ob->obmat[3][2]+ v3d->persmat[3][3]; + pixsize*= v3d->pixsize; + if(part->draw_size==0.0) + pixsize*=2.0; + else + pixsize*=part->draw_size; + break; + case PART_DRAW_OB: + if(part->dup_ob==0) + draw_as=PART_DRAW_DOT; + else + draw_as=0; + break; + case PART_DRAW_GR: + if(part->dup_group==0) + draw_as=PART_DRAW_DOT; + else + draw_as=0; + break; + case PART_DRAW_BB: + if(v3d->camera==0 && part->bb_ob==0){ +// XXX error("Billboards need an active camera or a target object!"); + + draw_as=part->draw_as=PART_DRAW_DOT; + + if(part->draw_size) + glPointSize(part->draw_size); + else + glPointSize(2.0); /* default dot size */ + } + else if(part->bb_ob) + bb_ob=part->bb_ob; + else + bb_ob=v3d->camera; + + if(part->bb_align<PART_BB_VIEW) + onevec[part->bb_align]=1.0f; + break; + case PART_DRAW_PATH: + break; + } + if(part->draw & PART_DRAW_SIZE && part->draw_as!=PART_DRAW_CIRC){ + Mat4CpyMat4(imat, v3d->viewinv); + Normalize(imat[0]); + Normalize(imat[1]); + } + +/* 4. */ + if(draw_as && draw_as!=PART_DRAW_PATH){ + if(draw_as!=PART_DRAW_CIRC){ + switch(draw_as){ + case PART_DRAW_AXIS: + case PART_DRAW_CROSS: + if(draw_as!=PART_DRAW_CROSS || create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*6*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*6*3*sizeof(float), "particle_vdata"); + break; + case PART_DRAW_LINE: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*2*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*2*3*sizeof(float), "particle_vdata"); + break; + case PART_DRAW_BB: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_vdata"); + ndata=MEM_callocN((totpart+totchild)*(path_nbr+1)*4*3*sizeof(float), "particle_vdata"); + break; + default: + if(create_cdata) + cdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*3*sizeof(float), "particle_cdata"); + vdata=MEM_callocN((totpart+totchild)*(path_nbr+1)*3*sizeof(float), "particle_vdata"); + } + } + + if(part->draw&PART_DRAW_VEL && draw_as!=PART_DRAW_LINE) + vedata=MEM_callocN((totpart+totchild)*2*3*(path_nbr+1)*sizeof(float), "particle_vedata"); + + vd=vdata; + ved=vedata; + cd=cdata; + nd=ndata; + + psys->lattice=psys_get_lattice(ob,psys); + } + + if(draw_as){ +/* 5. */ + for(a=0,pa=pars; a<totpart+totchild; a++, pa++){ + if(a<totpart){ + if(totchild && (part->draw&PART_DRAW_PARENT)==0) continue; + if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; + + pa_time=(cfra-pa->time)/pa->lifetime; + pa_size=pa->size; + + if((part->flag&PART_ABS_TIME)==0){ + if(ma && ma->ipo){ + IpoCurve *icu; + + /* correction for lifetime */ + calc_ipo(ma->ipo, 100.0f*pa_time); + + for(icu = ma->ipo->curve.first; icu; icu=icu->next) { + if(icu->adrcode == MA_COL_R) + ma_r = icu->curval; + else if(icu->adrcode == MA_COL_G) + ma_g = icu->curval; + else if(icu->adrcode == MA_COL_B) + ma_b = icu->curval; + } + } + if(part->ipo) { + IpoCurve *icu; + + /* correction for lifetime */ + calc_ipo(part->ipo, 100*pa_time); + + for(icu = part->ipo->curve.first; icu; icu=icu->next) { + if(icu->adrcode == PART_SIZE) + pa_size = icu->curval; + } + } + } + + r_tilt=1.0f+pa->r_ave[0]; + + if(path_nbr){ + cache=psys->pathcache[a]; + k_max=(int)(cache->steps); + } + } + else{ + ChildParticle *cpa= &psys->child[a-totpart]; + + pa_time=psys_get_child_time(psys,cpa,cfra); + + if((part->flag&PART_ABS_TIME)==0) { + if(ma && ma->ipo){ + IpoCurve *icu; + + /* correction for lifetime */ + calc_ipo(ma->ipo, 100.0f*pa_time); + + for(icu = ma->ipo->curve.first; icu; icu=icu->next) { + if(icu->adrcode == MA_COL_R) + ma_r = icu->curval; + else if(icu->adrcode == MA_COL_G) + ma_g = icu->curval; + else if(icu->adrcode == MA_COL_B) + ma_b = icu->curval; + } + } + } + + pa_size=psys_get_child_size(psys,cpa,cfra,0); + + r_tilt=2.0f*cpa->rand[2]; + if(path_nbr){ + cache=psys->childcache[a-totpart]; + k_max=(int)(cache->steps); + } + } + + if(draw_as!=PART_DRAW_PATH){ + int next_pa=0; + for(k=0; k<=path_nbr; k++){ + if(draw_keys){ + state.time=(float)k/(float)path_nbr; + psys_get_particle_on_path(ob,psys,a,&state,1); + } + else if(path_nbr){ + if(k<=k_max){ + VECCOPY(state.co,(cache+k)->co); + VECCOPY(state.vel,(cache+k)->vel); + QUATCOPY(state.rot,(cache+k)->rot); + } + else + continue; + } + else{ + state.time=cfra; + if(psys_get_particle_state(ob,psys,a,&state,0)==0){ + next_pa=1; + break; + } + } + + switch(draw_as){ + case PART_DRAW_DOT: + if(cd) { + cd[0]=ma_r; + cd[1]=ma_g; + cd[2]=ma_b; + cd+=3; + } + if(vd){ + VECCOPY(vd,state.co) vd+=3; + } + break; + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + vec[0]=2.0f*pixsize; + vec[1]=vec[2]=0.0; + QuatMulVecf(state.rot,vec); + if(draw_as==PART_DRAW_AXIS){ + cd[1]=cd[2]=cd[4]=cd[5]=0.0; + cd[0]=cd[3]=1.0; + cd[6]=cd[8]=cd[9]=cd[11]=0.0; + cd[7]=cd[10]=1.0; + cd[13]=cd[12]=cd[15]=cd[16]=0.0; + cd[14]=cd[17]=1.0; + cd+=18; + + VECCOPY(vec2,state.co); + } + else { + if(cd) { + cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r; + cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g; + cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b; + cd+=18; + } + VECSUB(vec2,state.co,vec); + } + + VECADD(vec,state.co,vec); + VECCOPY(vd,vec); vd+=3; + VECCOPY(vd,vec2); vd+=3; + + vec[1]=2.0f*pixsize; + vec[0]=vec[2]=0.0; + QuatMulVecf(state.rot,vec); + if(draw_as==PART_DRAW_AXIS){ + VECCOPY(vec2,state.co); + } + else VECSUB(vec2,state.co,vec); + + VECADD(vec,state.co,vec); + VECCOPY(vd,vec); vd+=3; + VECCOPY(vd,vec2); vd+=3; + + vec[2]=2.0f*pixsize; + vec[0]=vec[1]=0.0; + QuatMulVecf(state.rot,vec); + if(draw_as==PART_DRAW_AXIS){ + VECCOPY(vec2,state.co); + } + else VECSUB(vec2,state.co,vec); + + VECADD(vec,state.co,vec); + + VECCOPY(vd,vec); vd+=3; + VECCOPY(vd,vec2); vd+=3; + break; + case PART_DRAW_LINE: + VECCOPY(vec,state.vel); + Normalize(vec); + if(part->draw & PART_DRAW_VEL_LENGTH) + VecMulf(vec,VecLength(state.vel)); + VECADDFAC(vd,state.co,vec,-part->draw_line[0]); vd+=3; + VECADDFAC(vd,state.co,vec,part->draw_line[1]); vd+=3; + if(cd) { + cd[0]=cd[3]=ma_r; + cd[1]=cd[4]=ma_g; + cd[2]=cd[5]=ma_b; + cd+=3; + } + break; + case PART_DRAW_CIRC: + if(create_cdata) + glColor3f(ma_r,ma_g,ma_b); + drawcircball(GL_LINE_LOOP, state.co, pixsize, imat); + break; + case PART_DRAW_BB: + if(cd) { + cd[0]=cd[3]=cd[6]=cd[9]=ma_r; + cd[1]=cd[4]=cd[7]=cd[10]=ma_g; + cd[2]=cd[5]=cd[8]=cd[11]=ma_b; + cd+=12; + } + if(part->draw&PART_DRAW_BB_LOCK && part->bb_align==PART_BB_VIEW){ + VECCOPY(xvec,bb_ob->obmat[0]); + Normalize(xvec); + VECCOPY(yvec,bb_ob->obmat[1]); + Normalize(yvec); + VECCOPY(zvec,bb_ob->obmat[2]); + Normalize(zvec); + } + else if(part->bb_align==PART_BB_VEL){ + float temp[3]; + VECCOPY(temp,state.vel); + Normalize(temp); + VECSUB(zvec,bb_ob->obmat[3],state.co); + if(part->draw&PART_DRAW_BB_LOCK){ + float fac=-Inpf(zvec,temp); + VECADDFAC(zvec,zvec,temp,fac); + } + Normalize(zvec); + Crossf(xvec,temp,zvec); + Normalize(xvec); + Crossf(yvec,zvec,xvec); + } + else{ + VECSUB(zvec,bb_ob->obmat[3],state.co); + if(part->draw&PART_DRAW_BB_LOCK) + zvec[part->bb_align]=0.0f; + Normalize(zvec); + + if(part->bb_align<PART_BB_VIEW) + Crossf(xvec,onevec,zvec); + else + Crossf(xvec,bb_ob->obmat[1],zvec); + Normalize(xvec); + Crossf(yvec,zvec,xvec); + } + + VECCOPY(vec,xvec); + VECCOPY(vec2,yvec); + + VecMulf(xvec,cos(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VecMulf(vec2,sin(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VECADD(xvec,xvec,vec2); + + VecMulf(yvec,cos(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VecMulf(vec,-sin(part->bb_tilt*(1.0f-part->bb_rand_tilt*r_tilt)*(float)M_PI)); + VECADD(yvec,yvec,vec); + + VecMulf(xvec,pa_size); + VecMulf(yvec,pa_size); + + VECADDFAC(bb_center,state.co,xvec,part->bb_offset[0]); + VECADDFAC(bb_center,bb_center,yvec,part->bb_offset[1]); + + VECADD(vd,bb_center,xvec); + VECADD(vd,vd,yvec); vd+=3; + + VECSUB(vd,bb_center,xvec); + VECADD(vd,vd,yvec); vd+=3; + + VECSUB(vd,bb_center,xvec); + VECSUB(vd,vd,yvec); vd+=3; + + VECADD(vd,bb_center,xvec); + VECSUB(vd,vd,yvec); vd+=3; + + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + VECCOPY(nd, zvec); nd+=3; + break; + } + + if(vedata){ + VECCOPY(ved,state.co); + ved+=3; + VECCOPY(vel,state.vel); + VecMulf(vel,timestep); + VECADD(ved,state.co,vel); + ved+=3; + } + + if(part->draw & PART_DRAW_SIZE){ + setlinestyle(3); + drawcircball(GL_LINE_LOOP, state.co, pa_size, imat); + setlinestyle(0); + } + + totpoint++; + } + if(next_pa) + continue; + if(part->draw&PART_DRAW_NUM && !(G.f & G_RENDER_SHADOW)){ + /* in path drawing state.co is the end point */ + glRasterPos3f(state.co[0], state.co[1], state.co[2]); + sprintf(val," %i",a); + BMF_DrawString(G.font, val); + } + } + } +/* 6. */ + + glGetIntegerv(GL_POLYGON_MODE, polygonmode); + glDisableClientState(GL_NORMAL_ARRAY); + + if(draw_as != PART_DRAW_CIRC){ + if(draw_as==PART_DRAW_PATH){ + ParticleCacheKey **cache, *path; + float *cd2=0,*cdata2=0; + + glEnableClientState(GL_VERTEX_ARRAY); + + if(dt > OB_WIRE) { + glEnableClientState(GL_NORMAL_ARRAY); + + if(part->draw&PART_DRAW_MAT_COL) + glEnableClientState(GL_COLOR_ARRAY); + + glEnable(GL_LIGHTING); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHTING); + UI_ThemeColor(TH_WIRE); + } + + if(totchild && (part->draw&PART_DRAW_PARENT)==0) + totpart=0; + + cache=psys->pathcache; + for(a=0, pa=psys->particles; a<totpart; a++, pa++){ + path=cache[a]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if(dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); + if(part->draw&PART_DRAW_MAT_COL) + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); + } + + glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); + } + + cache=psys->childcache; + for(a=0; a<totchild; a++){ + path=cache[a]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if(dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); + if(part->draw&PART_DRAW_MAT_COL) + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); + } + + glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); + } + + if(dt > OB_WIRE) { + if(part->draw&PART_DRAW_MAT_COL) + glDisable(GL_COLOR_ARRAY); + glDisable(GL_COLOR_MATERIAL); + } + + if(cdata2) + MEM_freeN(cdata2); + cd2=cdata2=0; + + glLineWidth(1.0f); + + /* draw particle edit mode key points*/ + } + + if(draw_as!=PART_DRAW_PATH){ + glDisableClientState(GL_COLOR_ARRAY); + + if(vdata){ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vdata); + } + else + glDisableClientState(GL_VERTEX_ARRAY); + + if(ndata && dt>OB_WIRE){ + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, ndata); + glEnable(GL_LIGHTING); + } + else{ + glDisableClientState(GL_NORMAL_ARRAY); + glDisable(GL_LIGHTING); + } + + if(cdata){ + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(3, GL_FLOAT, 0, cdata); + } + + switch(draw_as){ + case PART_DRAW_AXIS: + case PART_DRAW_CROSS: + glDrawArrays(GL_LINES, 0, 6*totpoint); + break; + case PART_DRAW_LINE: + glDrawArrays(GL_LINES, 0, 2*totpoint); + break; + case PART_DRAW_BB: + if(dt<=OB_WIRE) + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + + glDrawArrays(GL_QUADS, 0, 4*totpoint); + break; + default: + glDrawArrays(GL_POINTS, 0, totpoint); + break; + } + } + + } + if(vedata){ + glDisableClientState(GL_COLOR_ARRAY); + cpack(0xC0C0C0); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vedata); + + glDrawArrays(GL_LINES, 0, 2*totpoint); + } + + glPolygonMode(GL_FRONT, polygonmode[0]); + glPolygonMode(GL_BACK, polygonmode[1]); + } + +/* 7. */ + + glDisable(GL_LIGHTING); + glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + if(states) + MEM_freeN(states); + if(vdata) + MEM_freeN(vdata); + if(vedata) + MEM_freeN(vedata); + if(cdata) + MEM_freeN(cdata); + if(ndata) + MEM_freeN(ndata); + + psys->flag &= ~PSYS_DRAWING; + + if(psys->lattice){ + end_latt_deform(); + psys->lattice=0; + } + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + wmMultMatrix(CTX_wm_window(C), ob->obmat); // bring back local matrix for dtx +} + +static void draw_particle_edit(const bContext *C, Scene *scene, View3D *v3d, Object *ob, ParticleSystem *psys, int dt) +{ + ParticleEdit *edit = psys->edit; + ParticleData *pa; + ParticleCacheKey **path; + ParticleEditKey *key; + ParticleEditSettings *pset = NULL; // XXX PE_settings(); + int i, k, totpart = psys->totpart, totchild=0, timed = pset->draw_timed; + char nosel[4], sel[4]; + float sel_col[3]; + float nosel_col[3]; + char val[32]; + + /* create path and child path cache if it doesn't exist already */ + if(psys->pathcache==0){ +// XXX PE_hide_keys_time(psys,CFRA); + psys_cache_paths(ob,psys,CFRA,0); + } + if(psys->pathcache==0) + return; + + if(pset->flag & PE_SHOW_CHILD && psys->part->draw_as == PART_DRAW_PATH) { + if(psys->childcache==0) + psys_cache_child_paths(ob, psys, CFRA, 0); + } + else if(!(pset->flag & PE_SHOW_CHILD) && psys->childcache) + free_child_path_cache(psys); + + /* opengl setup */ + if((v3d->flag & V3D_ZBUF_SELECT)==0) + glDisable(GL_DEPTH_TEST); + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + /* get selection theme colors */ + UI_GetThemeColor3ubv(TH_VERTEX_SELECT, sel); + UI_GetThemeColor3ubv(TH_VERTEX, nosel); + sel_col[0]=(float)sel[0]/255.0f; + sel_col[1]=(float)sel[1]/255.0f; + sel_col[2]=(float)sel[2]/255.0f; + nosel_col[0]=(float)nosel[0]/255.0f; + nosel_col[1]=(float)nosel[1]/255.0f; + nosel_col[2]=(float)nosel[2]/255.0f; + + if(psys->childcache) + totchild = psys->totchildcache; + + /* draw paths */ + if(timed) + glEnable(GL_BLEND); + + glEnableClientState(GL_VERTEX_ARRAY); + + if(dt > OB_WIRE) { + /* solid shaded with lighting */ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + } + else { + /* flat wire color */ + glDisableClientState(GL_NORMAL_ARRAY); + glDisable(GL_LIGHTING); + UI_ThemeColor(TH_WIRE); + } + + /* only draw child paths with lighting */ + if(dt > OB_WIRE) + glEnable(GL_LIGHTING); + + if(psys->part->draw_as == PART_DRAW_PATH) { + for(i=0, path=psys->childcache; i<totchild; i++,path++){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); + if(dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + } + + glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); + } + } + + if(dt > OB_WIRE) + glDisable(GL_LIGHTING); + + if(pset->brushtype == PE_BRUSH_WEIGHT) { + glLineWidth(2.0f); + glEnableClientState(GL_COLOR_ARRAY); + glDisable(GL_LIGHTING); + } + + /* draw parents last without lighting */ + for(i=0, pa=psys->particles, path = psys->pathcache; i<totpart; i++, pa++, path++){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); + if(dt > OB_WIRE) + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); + if(dt > OB_WIRE || pset->brushtype == PE_BRUSH_WEIGHT) + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + + glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); + } + + /* draw edit vertices */ + if(scene->selectmode!=SCE_SELECT_PATH){ + glDisableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glDisable(GL_LIGHTING); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if(scene->selectmode==SCE_SELECT_POINT){ + float *cd=0,*cdata=0; + cd=cdata=MEM_callocN(edit->totkeys*(timed?4:3)*sizeof(float), "particle edit color data"); + + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++){ + if(key->flag&PEK_SELECT){ + VECCOPY(cd,sel_col); + } + else{ + VECCOPY(cd,nosel_col); + } + if(timed) + *(cd+3) = (key->flag&PEK_HIDE)?0.0f:1.0f; + cd += (timed?4:3); + } + } + cd=cdata; + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + if((pa->flag & PARS_HIDE)==0){ + glVertexPointer(3, GL_FLOAT, sizeof(ParticleEditKey), edit->keys[i]->world_co); + glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd); + glDrawArrays(GL_POINTS, 0, pa->totkey); + } + cd += (timed?4:3) * pa->totkey; + + if((pset->flag&PE_SHOW_TIME) && (pa->flag&PARS_HIDE)==0 && !(G.f & G_RENDER_SHADOW)){ + for(k=0, key=edit->keys[i]+k; k<pa->totkey; k++, key++){ + if(key->flag & PEK_HIDE) continue; + + glRasterPos3fv(key->world_co); + sprintf(val," %.1f",*key->time); + BMF_DrawString(G.font, val); + } + } + } + if(cdata) + MEM_freeN(cdata); + cd=cdata=0; + } + else if(scene->selectmode == SCE_SELECT_END){ + for(i=0, pa=psys->particles; i<totpart; i++, pa++){ + if((pa->flag & PARS_HIDE)==0){ + key = edit->keys[i] + pa->totkey - 1; + if(key->flag & PEK_SELECT) + glColor3fv(sel_col); + else + glColor3fv(nosel_col); + /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ + glBegin(GL_POINTS); + glVertex3fv(key->world_co); + glEnd(); + + if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){ + glRasterPos3fv(key->world_co); + sprintf(val," %.1f",*key->time); + BMF_DrawString(G.font, val); + } + } + } + } + } + + glDisable(GL_BLEND); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnable(GL_DEPTH_TEST); + glLineWidth(1.0f); + + wmMultMatrix(CTX_wm_window(C), ob->obmat); // bring back local matrix for dtx + glPointSize(1.0); +} + +unsigned int nurbcol[8]= { + 0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 }; + +static void tekenhandlesN(Nurb *nu, short sel) +{ + BezTriple *bezt; + float *fp; + unsigned int *col; + int a; + + if(nu->hide || (G.f & G_HIDDENHANDLES)) return; + + glBegin(GL_LINES); + + if( (nu->type & 7)==1) { + if(sel) col= nurbcol+4; + else col= nurbcol; + + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->hide==0) { + if( (bezt->f2 & SELECT)==sel) { + fp= bezt->vec[0]; + + cpack(col[bezt->h1]); + glVertex3fv(fp); + glVertex3fv(fp+3); + + cpack(col[bezt->h2]); + glVertex3fv(fp+3); + glVertex3fv(fp+6); + } + else if( (bezt->f1 & SELECT)==sel) { + fp= bezt->vec[0]; + + cpack(col[bezt->h1]); + glVertex3fv(fp); + glVertex3fv(fp+3); + } + else if( (bezt->f3 & SELECT)==sel) { + fp= bezt->vec[1]; + + cpack(col[bezt->h2]); + glVertex3fv(fp); + glVertex3fv(fp+3); + } + } + bezt++; + } + } + glEnd(); +} + +static void tekenvertsN(Nurb *nu, short sel) +{ + BezTriple *bezt; + BPoint *bp; + float size; + int a; + + if(nu->hide) return; + + if(sel) UI_ThemeColor(TH_VERTEX_SELECT); + else UI_ThemeColor(TH_VERTEX); + + size= UI_GetThemeValuef(TH_VERTEX_SIZE); + glPointSize(size); + + bglBegin(GL_POINTS); + + if((nu->type & 7)==1) { + + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->hide==0) { + if (G.f & G_HIDDENHANDLES) { + if((bezt->f2 & SELECT)==sel) bglVertex3fv(bezt->vec[1]); + } else { + if((bezt->f1 & SELECT)==sel) bglVertex3fv(bezt->vec[0]); + if((bezt->f2 & SELECT)==sel) bglVertex3fv(bezt->vec[1]); + if((bezt->f3 & SELECT)==sel) bglVertex3fv(bezt->vec[2]); + } + } + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(bp->hide==0) { + if((bp->f1 & SELECT)==sel) bglVertex3fv(bp->vec); + } + bp++; + } + } + + bglEnd(); + glPointSize(1.0); +} + +static void draw_editnurb(Object *ob, Nurb *nurb, int sel) +{ + Nurb *nu; + BPoint *bp, *bp1; + int a, b, ofs; + + nu= nurb; + while(nu) { + if(nu->hide==0) { + switch(nu->type & 7) { + case CU_POLY: + cpack(nurbcol[3]); + bp= nu->bp; + for(b=0; b<nu->pntsv; b++) { + if(nu->flagu & 1) glBegin(GL_LINE_LOOP); + else glBegin(GL_LINE_STRIP); + + for(a=0; a<nu->pntsu; a++, bp++) { + glVertex3fv(bp->vec); + } + + glEnd(); + } + break; + case CU_NURBS: + + bp= nu->bp; + for(b=0; b<nu->pntsv; b++) { + bp1= bp; + bp++; + for(a=nu->pntsu-1; a>0; a--, bp++) { + if(bp->hide==0 && bp1->hide==0) { + if(sel) { + if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT ) ) { + cpack(nurbcol[5]); + + glBegin(GL_LINE_STRIP); + glVertex3fv(bp->vec); + glVertex3fv(bp1->vec); + glEnd(); + } + } + else { + if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ); + else { + cpack(nurbcol[1]); + + glBegin(GL_LINE_STRIP); + glVertex3fv(bp->vec); + glVertex3fv(bp1->vec); + glEnd(); + } + } + } + bp1= bp; + } + } + if(nu->pntsv > 1) { /* surface */ + + ofs= nu->pntsu; + for(b=0; b<nu->pntsu; b++) { + bp1= nu->bp+b; + bp= bp1+ofs; + for(a=nu->pntsv-1; a>0; a--, bp+=ofs) { + if(bp->hide==0 && bp1->hide==0) { + if(sel) { + if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ) { + cpack(nurbcol[7]); + + glBegin(GL_LINE_STRIP); + glVertex3fv(bp->vec); + glVertex3fv(bp1->vec); + glEnd(); + } + } + else { + if( (bp->f1 & SELECT) && ( bp1->f1 & SELECT) ); + else { + cpack(nurbcol[3]); + + glBegin(GL_LINE_STRIP); + glVertex3fv(bp->vec); + glVertex3fv(bp1->vec); + glEnd(); + } + } + } + bp1= bp; + } + } + + } + break; + } + } + nu= nu->next; + } +} + +static void drawnurb(Scene *scene, View3D *v3d, Base *base, Nurb *nurb, int dt) +{ + Object *ob= base->object; + Curve *cu = ob->data; + Nurb *nu; + BevList *bl; + +// XXX retopo_matrix_update(v3d); + + /* DispList */ + UI_ThemeColor(TH_WIRE); + drawDispList(scene, v3d, base, dt); + + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + + /* first non-selected handles */ + for(nu=nurb; nu; nu=nu->next) { + if((nu->type & 7)==CU_BEZIER) { + tekenhandlesN(nu, 0); + } + } + draw_editnurb(ob, nurb, 0); + draw_editnurb(ob, nurb, 1); + /* selected handles */ + for(nu=nurb; nu; nu=nu->next) { + if((nu->type & 7)==1) tekenhandlesN(nu, 1); + tekenvertsN(nu, 0); + } + + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + + /* direction vectors for 3d curve paths + when at its lowest, dont render normals */ + if(cu->flag & CU_3D && scene->editbutsize > 0.0015) { + UI_ThemeColor(TH_WIRE); + for (bl=cu->bev.first,nu=nurb; nu && bl; bl=bl->next,nu=nu->next) { + BevPoint *bevp= (BevPoint *)(bl+1); + int nr= bl->nr; + int skip= nu->resolu/16; + + while (nr-->0) { /* accounts for empty bevel lists */ + float fac= bevp->radius * scene->editbutsize; + float ox,oy,oz; // Offset perpendicular to the curve + float dx,dy,dz; // Delta along the curve + + ox = fac*bevp->mat[0][0]; + oy = fac*bevp->mat[0][1]; + oz = fac*bevp->mat[0][2]; + + dx = fac*bevp->mat[2][0]; + dy = fac*bevp->mat[2][1]; + dz = fac*bevp->mat[2][2]; + + glBegin(GL_LINE_STRIP); + glVertex3f(bevp->x - ox - dx, bevp->y - oy - dy, bevp->z - oz - dz); + glVertex3f(bevp->x, bevp->y, bevp->z); + glVertex3f(bevp->x + ox - dx, bevp->y + oy - dy, bevp->z + oz - dz); + glEnd(); + + bevp += skip+1; + nr -= skip; + } + } + } + + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + + for(nu=nurb; nu; nu=nu->next) { + tekenvertsN(nu, 1); + } + + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); +} + +/* draw a sphere for use as an empty drawtype */ +static void draw_empty_sphere (float size) +{ + float cent=0; + GLUquadricObj *qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + + glPushMatrix(); + glTranslatef(cent, cent, cent); + glScalef(size, size, size); + gluSphere(qobj, 1.0, 8, 5); + + glPopMatrix(); + + gluDeleteQuadric(qobj); +} + +/* draw a cone for use as an empty drawtype */ +static void draw_empty_cone (float size) +{ + float cent=0; + float radius; + GLUquadricObj *qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + + + glPushMatrix(); + + radius = size; + glTranslatef(cent,cent, cent); + glScalef(radius, 2.0*size, radius); + glRotatef(-90., 1.0, 0.0, 0.0); + gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); + + glPopMatrix(); + + gluDeleteQuadric(qobj); +} + +/* draw points on curve speed handles */ +static void curve_draw_speed(Scene *scene, Object *ob) +{ + Curve *cu= ob->data; + IpoCurve *icu; + BezTriple *bezt; + float loc[4], dir[3]; + int a; + + if(cu->ipo==NULL) + return; + + icu= cu->ipo->curve.first; + if(icu==NULL || icu->totvert<2) + return; + + glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); + bglBegin(GL_POINTS); + + for(a=0, bezt= icu->bezt; a<icu->totvert; a++, bezt++) { + if( where_on_path(ob, bezt->vec[1][1], loc, dir)) { + UI_ThemeColor((bezt->f2 & SELECT) && ob==OBACT?TH_VERTEX_SELECT:TH_VERTEX); + bglVertex3fv(loc); + } + } + + glPointSize(1.0); + bglEnd(); +} + + +static void tekentextcurs(void) +{ + cpack(0); + + set_inverted_drawing(1); + glBegin(GL_QUADS); + glVertex2fv(G.textcurs[0]); + glVertex2fv(G.textcurs[1]); + glVertex2fv(G.textcurs[2]); + glVertex2fv(G.textcurs[3]); + glEnd(); + set_inverted_drawing(0); +} + +static void drawspiral(float *cent, float rad, float tmat[][4], int start) +{ + float vec[3], vx[3], vy[3]; + int a, tot=32; + char inverse=0; + + if (start < 0) { + inverse = 1; + start *= -1; + } + + VECCOPY(vx, tmat[0]); + VECCOPY(vy, tmat[1]); + VecMulf(vx, rad); + VecMulf(vy, rad); + + VECCOPY(vec, cent); + + if (inverse==0) { + for(a=0; a<tot; a++) { + if (a+start>31) + start=-a + 1; + glBegin(GL_LINES); + glVertex3fv(vec); + vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)a/(float)tot) + *(cosval+a+start) * (vy[0] * (float)a/(float)tot); + vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)a/(float)tot) + *(cosval+a+start) * (vy[1] * (float)a/(float)tot); + vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)a/(float)tot) + *(cosval+a+start) * (vy[2] * (float)a/(float)tot); + glVertex3fv(vec); + glEnd(); + } + } + else { + a=0; + vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot); + vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot); + vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot); + for(a=0; a<tot; a++) { + if (a+start>31) + start=-a + 1; + glBegin(GL_LINES); + glVertex3fv(vec); + vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot); + vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot); + vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot); + glVertex3fv(vec); + glEnd(); + } + } +} + +/* draws a circle on x-z plane given the scaling of the circle, assuming that + * all required matrices have been set (used for drawing empties) + */ +static void drawcircle_size(float size) +{ + float x, y; + short degrees; + + glBegin(GL_LINE_LOOP); + + /* coordinates are: cos(degrees*11.25)=x, sin(degrees*11.25)=y, 0.0f=z */ + for (degrees=0; degrees<32; degrees++) { + x= *(cosval + degrees); + y= *(sinval + degrees); + + glVertex3f(x*size, 0.0f, y*size); + } + + glEnd(); + +} + +/* needs fixing if non-identity matrice used */ +static void drawtube(float *vec, float radius, float height, float tmat[][4]) +{ + float cur[3]; + drawcircball(GL_LINE_LOOP, vec, radius, tmat); + + VecCopyf(cur,vec); + cur[2]+=height; + + drawcircball(GL_LINE_LOOP, cur, radius, tmat); + + glBegin(GL_LINES); + glVertex3f(vec[0]+radius,vec[1],vec[2]); + glVertex3f(cur[0]+radius,cur[1],cur[2]); + glVertex3f(vec[0]-radius,vec[1],vec[2]); + glVertex3f(cur[0]-radius,cur[1],cur[2]); + glVertex3f(vec[0],vec[1]+radius,vec[2]); + glVertex3f(cur[0],cur[1]+radius,cur[2]); + glVertex3f(vec[0],vec[1]-radius,vec[2]); + glVertex3f(cur[0],cur[1]-radius,cur[2]); + glEnd(); +} +/* needs fixing if non-identity matrice used */ +static void drawcone(float *vec, float radius, float height, float tmat[][4]) +{ + float cur[3]; + + VecCopyf(cur,vec); + cur[2]+=height; + + drawcircball(GL_LINE_LOOP, cur, radius, tmat); + + glBegin(GL_LINES); + glVertex3f(vec[0],vec[1],vec[2]); + glVertex3f(cur[0]+radius,cur[1],cur[2]); + glVertex3f(vec[0],vec[1],vec[2]); + glVertex3f(cur[0]-radius,cur[1],cur[2]); + glVertex3f(vec[0],vec[1],vec[2]); + glVertex3f(cur[0],cur[1]+radius,cur[2]); + glVertex3f(vec[0],vec[1],vec[2]); + glVertex3f(cur[0],cur[1]-radius,cur[2]); + glEnd(); +} +/* return 1 if nothing was drawn */ +static int drawmball(const bContext *C, Scene *scene, View3D *v3d, Base *base, int dt) +{ + Object *ob= base->object; + MetaBall *mb; + MetaElem *ml; + float imat[4][4], tmat[4][4]; + int code= 1; + + mb= ob->data; + + if(ob==G.obedit) { + UI_ThemeColor(TH_WIRE); + if((G.f & G_PICKSEL)==0 ) drawDispList(scene, v3d, base, dt); + ml= editelems.first; + } + else { + if((base->flag & OB_FROMDUPLI)==0) + drawDispList(scene, v3d, base, dt); + ml= mb->elems.first; + } + + if(ml==NULL) return 1; + + /* in case solid draw, reset wire colors */ + if(ob!=G.obedit && (ob->flag & SELECT)) { + if(ob==OBACT) UI_ThemeColor(TH_ACTIVE); + else UI_ThemeColor(TH_SELECT); + } + else UI_ThemeColor(TH_WIRE); + + wmGetMatrix(CTX_wm_window(C), tmat); + Mat4Invert(imat, tmat); + Normalize(imat[0]); + Normalize(imat[1]); + + while(ml) { + + /* draw radius */ + if(ob==G.obedit) { + if((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) cpack(0xA0A0F0); + else cpack(0x3030A0); + + if(G.f & G_PICKSEL) { + ml->selcol1= code; + glLoadName(code++); + } + } + drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); + + /* draw stiffness */ + if(ob==G.obedit) { + if((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) cpack(0xA0F0A0); + else cpack(0x30A030); + + if(G.f & G_PICKSEL) { + ml->selcol2= code; + glLoadName(code++); + } + drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad*atan(ml->s)/M_PI_2, imat); + } + + ml= ml->next; + } + return 0; +} + +static void draw_forcefield(const bContext *C, Scene *scene, Object *ob) +{ + PartDeflect *pd= ob->pd; + float imat[4][4], tmat[4][4]; + float vec[3]= {0.0, 0.0, 0.0}; + int curcol; + float size; + + if(G.f & G_RENDER_SHADOW) + return; + + if(ob!=G.obedit && (ob->flag & SELECT)) { + if(ob==OBACT) curcol= TH_ACTIVE; + else curcol= TH_SELECT; + } + else curcol= TH_WIRE; + + /* scale size of circle etc with the empty drawsize */ + if (ob->type == OB_EMPTY) size = ob->empty_drawsize; + else size = 1.0; + + /* calculus here, is reused in PFIELD_FORCE */ + wmGetMatrix(CTX_wm_window(C), tmat); + Mat4Invert(imat, tmat); +// Normalize(imat[0]); // we don't do this because field doesnt scale either... apart from wind! +// Normalize(imat[1]); + + if (pd->forcefield == PFIELD_WIND) { + float force_val; + + Mat4One(tmat); + UI_ThemeColorBlend(curcol, TH_BACK, 0.5); + + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); + else + force_val = pd->f_strength; + force_val*= 0.1; + drawcircball(GL_LINE_LOOP, vec, size, tmat); + vec[2]= 0.5*force_val; + drawcircball(GL_LINE_LOOP, vec, size, tmat); + vec[2]= 1.0*force_val; + drawcircball(GL_LINE_LOOP, vec, size, tmat); + vec[2]= 1.5*force_val; + drawcircball(GL_LINE_LOOP, vec, size, tmat); + vec[2] = 0; /* reset vec for max dist circle */ + + } + else if (pd->forcefield == PFIELD_FORCE) { + float ffall_val; + + if (has_ipo_code(ob->ipo, OB_PD_FFALL)) + ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra); + else + ffall_val = pd->f_power; + + UI_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, vec, size, imat); + UI_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val)); + drawcircball(GL_LINE_LOOP, vec, size*1.5, imat); + UI_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val)); + drawcircball(GL_LINE_LOOP, vec, size*2.0, imat); + } + else if (pd->forcefield == PFIELD_VORTEX) { + float ffall_val, force_val; + + Mat4One(tmat); + if (has_ipo_code(ob->ipo, OB_PD_FFALL)) + ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra); + else + ffall_val = pd->f_power; + + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); + else + force_val = pd->f_strength; + + UI_ThemeColorBlend(curcol, TH_BACK, 0.7); + if (force_val < 0) { + drawspiral(vec, size*1.0, tmat, 1); + drawspiral(vec, size*1.0, tmat, 16); + } + else { + drawspiral(vec, size*1.0, tmat, -1); + drawspiral(vec, size*1.0, tmat, -16); + } + } + else if (pd->forcefield == PFIELD_GUIDE && ob->type==OB_CURVE) { + Curve *cu= ob->data; + if((cu->flag & CU_PATH) && cu->path && cu->path->data) { + float mindist, guidevec1[4], guidevec2[3]; + + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra); + else + mindist = pd->f_strength; + + /*path end*/ + setlinestyle(3); + where_on_path(ob, 1.0f, guidevec1, guidevec2); + UI_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); + + /*path beginning*/ + setlinestyle(0); + where_on_path(ob, 0.0f, guidevec1, guidevec2); + UI_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); + + VECCOPY(vec, guidevec1); /* max center */ + } + } + + setlinestyle(3); + UI_ThemeColorBlend(curcol, TH_BACK, 0.5); + + if(pd->falloff==PFIELD_FALL_SPHERE){ + /* as last, guide curve alters it */ + if(pd->flag & PFIELD_USEMAX) + drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat); + + if(pd->flag & PFIELD_USEMIN) + drawcircball(GL_LINE_LOOP, vec, pd->mindist, imat); + } + else if(pd->falloff==PFIELD_FALL_TUBE){ + float radius,distance; + + Mat4One(tmat); + + vec[0]=vec[1]=0.0f; + radius=(pd->flag&PFIELD_USEMAXR)?pd->maxrad:1.0f; + distance=(pd->flag&PFIELD_USEMAX)?pd->maxdist:0.0f; + vec[2]=distance; + distance=(pd->flag&PFIELD_POSZ)?-distance:-2.0f*distance; + + if(pd->flag & (PFIELD_USEMAX|PFIELD_USEMAXR)) + drawtube(vec,radius,distance,tmat); + + radius=(pd->flag&PFIELD_USEMINR)?pd->minrad:1.0f; + distance=(pd->flag&PFIELD_USEMIN)?pd->mindist:0.0f; + vec[2]=distance; + distance=(pd->flag&PFIELD_POSZ)?-distance:-2.0f*distance; + + if(pd->flag & (PFIELD_USEMIN|PFIELD_USEMINR)) + drawtube(vec,radius,distance,tmat); + } + else if(pd->falloff==PFIELD_FALL_CONE){ + float radius,distance; + + Mat4One(tmat); + + radius=(pd->flag&PFIELD_USEMAXR)?pd->maxrad:1.0f; + radius*=(float)M_PI/180.0f; + distance=(pd->flag&PFIELD_USEMAX)?pd->maxdist:0.0f; + + if(pd->flag & (PFIELD_USEMAX|PFIELD_USEMAXR)){ + drawcone(vec,distance*sin(radius),distance*cos(radius),tmat); + if((pd->flag & PFIELD_POSZ)==0) + drawcone(vec,distance*sin(radius),-distance*cos(radius),tmat); + } + + radius=(pd->flag&PFIELD_USEMINR)?pd->minrad:1.0f; + radius*=(float)M_PI/180.0f; + distance=(pd->flag&PFIELD_USEMIN)?pd->mindist:0.0f; + + if(pd->flag & (PFIELD_USEMIN|PFIELD_USEMINR)){ + drawcone(vec,distance*sin(radius),distance*cos(radius),tmat); + if((pd->flag & PFIELD_POSZ)==0) + drawcone(vec,distance*sin(radius),-distance*cos(radius),tmat); + } + } + setlinestyle(0); +} + +static void draw_box(float vec[8][3]) +{ + glBegin(GL_LINE_STRIP); + glVertex3fv(vec[0]); glVertex3fv(vec[1]);glVertex3fv(vec[2]); glVertex3fv(vec[3]); + glVertex3fv(vec[0]); glVertex3fv(vec[4]);glVertex3fv(vec[5]); glVertex3fv(vec[6]); + glVertex3fv(vec[7]); glVertex3fv(vec[4]); + glEnd(); + + glBegin(GL_LINES); + glVertex3fv(vec[1]); glVertex3fv(vec[5]); + glVertex3fv(vec[2]); glVertex3fv(vec[6]); + glVertex3fv(vec[3]); glVertex3fv(vec[7]); + glEnd(); +} + +/* uses boundbox, function used by Ketsji */ +void get_local_bounds(Object *ob, float *center, float *size) +{ + BoundBox *bb= object_get_boundbox(ob); + + if(bb==NULL) { + center[0]= center[1]= center[2]= 0.0; + VECCOPY(size, ob->size); + } + else { + size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]); + size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]); + size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]); + + center[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0; + center[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0; + center[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0; + } +} + + + +static void draw_bb_quadric(BoundBox *bb, short type) +{ + float size[3], cent[3]; + GLUquadricObj *qobj = gluNewQuadric(); + + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + + size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]); + size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]); + size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]); + + cent[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0; + cent[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0; + cent[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0; + + glPushMatrix(); + if(type==OB_BOUND_SPHERE) { + glTranslatef(cent[0], cent[1], cent[2]); + glScalef(size[0], size[1], size[2]); + gluSphere(qobj, 1.0, 8, 5); + } + else if(type==OB_BOUND_CYLINDER) { + float radius = size[0] > size[1] ? size[0] : size[1]; + glTranslatef(cent[0], cent[1], cent[2]-size[2]); + glScalef(radius, radius, 2.0*size[2]); + gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1); + } + else if(type==OB_BOUND_CONE) { + float radius = size[0] > size[1] ? size[0] : size[1]; + glTranslatef(cent[0], cent[2]-size[2], cent[1]); + glScalef(radius, 2.0*size[2], radius); + glRotatef(-90., 1.0, 0.0, 0.0); + gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); + } + glPopMatrix(); + + gluDeleteQuadric(qobj); +} + +static void draw_bounding_volume(Object *ob) +{ + BoundBox *bb=0; + + if(ob->type==OB_MESH) { + bb= mesh_get_bb(ob); + } + else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + bb= ( (Curve *)ob->data )->bb; + } + else if(ob->type==OB_MBALL) { + bb= ob->bb; + if(bb==0) { + makeDispListMBall(ob); + bb= ob->bb; + } + } + else { + drawcube(); + return; + } + + if(bb==0) return; + + if(ob->boundtype==OB_BOUND_BOX) draw_box(bb->vec); + else draw_bb_quadric(bb, ob->boundtype); + +} + +static void drawtexspace(Object *ob) +{ + float vec[8][3], loc[3], size[3]; + + if(ob->type==OB_MESH) { + mesh_get_texspace(ob->data, loc, NULL, size); + } + else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + Curve *cu= ob->data; + VECCOPY(size, cu->size); + VECCOPY(loc, cu->loc); + } + else if(ob->type==OB_MBALL) { + MetaBall *mb= ob->data; + VECCOPY(size, mb->size); + VECCOPY(loc, mb->loc); + } + else return; + + vec[0][0]=vec[1][0]=vec[2][0]=vec[3][0]= loc[0]-size[0]; + vec[4][0]=vec[5][0]=vec[6][0]=vec[7][0]= loc[0]+size[0]; + + vec[0][1]=vec[1][1]=vec[4][1]=vec[5][1]= loc[1]-size[1]; + vec[2][1]=vec[3][1]=vec[6][1]=vec[7][1]= loc[1]+size[1]; + + vec[0][2]=vec[3][2]=vec[4][2]=vec[7][2]= loc[2]-size[2]; + vec[1][2]=vec[2][2]=vec[5][2]=vec[6][2]= loc[2]+size[2]; + + setlinestyle(2); + + draw_box(vec); + + setlinestyle(0); +} + +/* draws wire outline */ +static void drawSolidSelect(View3D *v3d, Base *base) +{ + Object *ob= base->object; + + glLineWidth(2.0); + glDepthMask(0); + + if(ELEM3(ob->type, OB_FONT,OB_CURVE, OB_SURF)) { + Curve *cu = ob->data; + if (displist_has_faces(&cu->disp) && boundbox_clip(v3d, ob->obmat, cu->bb)) { + draw_index_wire= 0; + drawDispListwire(&cu->disp); + draw_index_wire= 1; + } + } else if (ob->type==OB_MBALL) { + if((base->flag & OB_FROMDUPLI)==0) + drawDispListwire(&ob->disp); + } + else if(ob->type==OB_ARMATURE) { + if(!(ob->flag & OB_POSEMODE)) + draw_armature(base, OB_WIRE, 0); + } + + glLineWidth(1.0); + glDepthMask(1); +} + +static void drawWireExtra(Scene *scene, View3D *v3d, Object *ob) +{ + if(ob!=G.obedit && (ob->flag & SELECT)) { + if(ob==OBACT) { + if(ob->flag & OB_FROMGROUP) UI_ThemeColor(TH_GROUP_ACTIVE); + else UI_ThemeColor(TH_ACTIVE); + } + else if(ob->flag & OB_FROMGROUP) + UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); + else + UI_ThemeColor(TH_SELECT); + } + else { + if(ob->flag & OB_FROMGROUP) + UI_ThemeColor(TH_GROUP); + else { + if(ob->dtx & OB_DRAWWIRE) { + glColor3ub(80,80,80); + } else { + UI_ThemeColor(TH_WIRE); + } + } + } + + bglPolygonOffset(1.0); + glDepthMask(0); // disable write in zbuffer, selected edge wires show better + + if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + Curve *cu = ob->data; + if (boundbox_clip(v3d, ob->obmat, cu->bb)) { + if (ob->type==OB_CURVE) + draw_index_wire= 0; + drawDispListwire(&cu->disp); + if (ob->type==OB_CURVE) + draw_index_wire= 1; + } + } else if (ob->type==OB_MBALL) { + drawDispListwire(&ob->disp); + } + + glDepthMask(1); + bglPolygonOffset(0.0); +} + +/* should be called in view space */ +static void draw_hooks(Object *ob) +{ + ModifierData *md; + float vec[3]; + + for (md=ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData*) md; + + VecMat4MulVecfl(vec, ob->obmat, hmd->cent); + + if(hmd->object) { + setlinestyle(3); + glBegin(GL_LINES); + glVertex3fv(hmd->object->obmat[3]); + glVertex3fv(vec); + glEnd(); + setlinestyle(0); + } + + glPointSize(3.0); + bglBegin(GL_POINTS); + bglVertex3fv(vec); + bglEnd(); + glPointSize(1.0); + } + } +} + +//<rcruiz> +void drawRBpivot(bRigidBodyJointConstraint *data) +{ + float radsPerDeg = 6.283185307179586232f / 360.f; + int axis; + float v1[3]= {data->pivX, data->pivY, data->pivZ}; + float eu[3]= {radsPerDeg*data->axX, radsPerDeg*data->axY, radsPerDeg*data->axZ}; + float mat[4][4]; + + if(G.f & G_RENDER_SHADOW) + return; + + EulToMat4(eu,mat); + glLineWidth (4.0f); + setlinestyle(2); + for (axis=0; axis<3; axis++) { + float dir[3] = {0,0,0}; + float v[3]= {data->pivX, data->pivY, data->pivZ}; + + dir[axis] = 1.f; + glBegin(GL_LINES); + Mat4MulVecfl(mat,dir); + v[0] += dir[0]; + v[1] += dir[1]; + v[2] += dir[2]; + glVertex3fv(v1); + glVertex3fv(v); + glEnd(); + glRasterPos3fv(v); + if (axis==0) + BMF_DrawString(G.font, "px"); + else if (axis==1) + BMF_DrawString(G.font, "py"); + else + BMF_DrawString(G.font, "pz"); + } + glLineWidth (1.0f); + setlinestyle(0); +} + +/* flag can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET */ +void draw_object(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) +{ + static int warning_recursive= 0; + Object *ob; + Curve *cu; + float cfraont; + float vec1[3], vec2[3]; + unsigned int col=0; + int sel, drawtype, colindex= 0, ipoflag; + int i, selstart, selend, empty_object=0; + short dt, dtx, zbufoff= 0; + + /* only once set now, will be removed too, should become a global standard */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ob= base->object; + + if (ob!=G.obedit) { + if (ob->restrictflag & OB_RESTRICT_VIEW) + return; + } + + /* xray delay? */ + if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) { + /* don't do xray in particle mode, need the z-buffer */ + if(!(G.f & G_PARTICLEEDIT)) { + /* xray and transp are set when it is drawing the 2nd/3rd pass */ + if(!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY)) { + add_view3d_after(v3d, base, V3D_XRAY, flag); + return; + } + } + } + + /* draw keys? */ + if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) { + if(flag==0 && warning_recursive==0 && ob!=G.obedit) { + if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) { + ListBase elems; + CfraElem *ce; + float temp[7][3]; + + warning_recursive= 1; + + elems.first= elems.last= 0; + // warning: no longer checks for certain ob-keys only... (so does this need to use the proper ipokeys then?) + make_cfra_list(ob->ipo, &elems); + + cfraont= (scene->r.cfra); + drawtype= v3d->drawtype; + if(drawtype>OB_WIRE) v3d->drawtype= OB_WIRE; + sel= base->flag; + memcpy(temp, &ob->loc, 7*3*sizeof(float)); + + ipoflag= ob->ipoflag; + ob->ipoflag &= ~OB_OFFS_OB; + + set_no_parent_ipo(1); + disable_speed_curve(1); + + if ((ob->ipoflag & OB_DRAWKEYSEL)==0) { + ce= elems.first; + while(ce) { + if(!ce->sel) { + (scene->r.cfra)= ce->cfra/scene->r.framelen; + + base->flag= 0; + + where_is_object_time(ob, (scene->r.cfra)); + draw_object(C, scene, ar, v3d, base, 0); + } + ce= ce->next; + } + } + + ce= elems.first; + while(ce) { + if(ce->sel) { + (scene->r.cfra)= ce->cfra/scene->r.framelen; + + base->flag= SELECT; + + where_is_object_time(ob, (scene->r.cfra)); + draw_object(C, scene, ar, v3d, base, 0); + } + ce= ce->next; + } + + set_no_parent_ipo(0); + disable_speed_curve(0); + + base->flag= sel; + ob->ipoflag= ipoflag; + + /* restore icu->curval */ + (scene->r.cfra)= cfraont; + + memcpy(&ob->loc, temp, 7*3*sizeof(float)); + where_is_object(ob); + v3d->drawtype= drawtype; + + BLI_freelistN(&elems); + + warning_recursive= 0; + } + } + } + + /* patch? children objects with a timeoffs change the parents. How to solve! */ + /* if( ((int)ob->ctime) != F_(scene->r.cfra)) where_is_object(ob); */ + + wmMultMatrix(CTX_wm_window(C), ob->obmat); + + /* which wire color */ + if((flag & DRAW_CONSTCOLOR) == 0) { + project_short(ar, v3d, ob->obmat[3], &base->sx); + + if((G.moving & G_TRANSFORM_OBJ) && (base->flag & (SELECT+BA_WAS_SEL))) UI_ThemeColor(TH_TRANSFORM); + else { + + if(ob->type==OB_LAMP) UI_ThemeColor(TH_LAMP); + else UI_ThemeColor(TH_WIRE); + + if((scene->basact)==base) { + if(base->flag & (SELECT+BA_WAS_SEL)) UI_ThemeColor(TH_ACTIVE); + } + else { + if(base->flag & (SELECT+BA_WAS_SEL)) UI_ThemeColor(TH_SELECT); + } + + // no theme yet + if(ob->id.lib) { + if(base->flag & (SELECT+BA_WAS_SEL)) colindex = 4; + else colindex = 3; + } + else if(warning_recursive==1) { + if(base->flag & (SELECT+BA_WAS_SEL)) { + if(scene->basact==base) colindex = 8; + else colindex= 7; + } + else colindex = 6; + } + else if(ob->flag & OB_FROMGROUP) { + if(base->flag & (SELECT+BA_WAS_SEL)) { + if(scene->basact==base) UI_ThemeColor(TH_GROUP_ACTIVE); + else UI_ThemeColorShade(TH_GROUP_ACTIVE, -16); + } + else UI_ThemeColor(TH_GROUP); + colindex= 0; + } + + } + + if(colindex) { + col= colortab[colindex]; + cpack(col); + } + } + + /* maximum drawtype */ + dt= MIN2(v3d->drawtype, ob->dt); + if(v3d->zbuf==0 && dt>OB_WIRE) dt= OB_WIRE; + dtx= 0; + + /* faceselect exception: also draw solid when dt==wire, except in editmode */ + if(ob==OBACT && (G.f & (G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT))) { + if(ob->type==OB_MESH) { + + if(ob==G.obedit); + else { + if(dt<OB_SOLID) + zbufoff= 1; + + dt= OB_SHADED; + glEnable(GL_DEPTH_TEST); + } + } + else { + if(dt<OB_SOLID) { + dt= OB_SOLID; + glEnable(GL_DEPTH_TEST); + zbufoff= 1; + } + } + } + + /* draw-extra supported for boundbox drawmode too */ + if(dt>=OB_BOUNDBOX ) { + + dtx= ob->dtx; + if(G.obedit==ob) { + // the only 2 extra drawtypes alowed in editmode + dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE); + } + + if(G.f & G_DRAW_EXT) { + if(ob->type==OB_EMPTY || ob->type==OB_CAMERA || ob->type==OB_LAMP) dt= OB_WIRE; + } + } + + /* draw outline for selected solid objects, mesh does itself */ + if((v3d->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) { + if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=G.obedit && (flag && DRAW_SCENESET)==0) { + if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { + drawSolidSelect(v3d, base); + } + } + } + + switch( ob->type) { + case OB_MESH: + if (!(base->flag&OB_RADIO)) { + empty_object= draw_mesh_object(scene, v3d, base, dt, flag); + if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself + } + + break; + case OB_FONT: + cu= ob->data; + if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0); + if(ob==G.obedit) { + tekentextcurs(); + + if (cu->flag & CU_FAST) { + cpack(0xFFFFFF); + set_inverted_drawing(1); + drawDispList(scene, v3d, base, OB_WIRE); + set_inverted_drawing(0); + } else { + drawDispList(scene, v3d, base, dt); + } + + if (cu->linewidth != 0.0) { + cpack(0xff44ff); + UI_ThemeColor(TH_WIRE); + VECCOPY(vec1, ob->orig); + VECCOPY(vec2, ob->orig); + vec1[0] += cu->linewidth; + vec2[0] += cu->linewidth; + vec1[1] += cu->linedist * cu->fsize; + vec2[1] -= cu->lines * cu->linedist * cu->fsize; + setlinestyle(3); + glBegin(GL_LINE_STRIP); + glVertex2fv(vec1); + glVertex2fv(vec2); + glEnd(); + setlinestyle(0); + } + + setlinestyle(3); + for (i=0; i<cu->totbox; i++) { + if (cu->tb[i].w != 0.0) { + if (i == (cu->actbox-1)) + UI_ThemeColor(TH_ACTIVE); + else + UI_ThemeColor(TH_WIRE); + vec1[0] = cu->tb[i].x; + vec1[1] = cu->tb[i].y + cu->fsize; + vec1[2] = 0.001; + glBegin(GL_LINE_STRIP); + glVertex3fv(vec1); + vec1[0] += cu->tb[i].w; + glVertex3fv(vec1); + vec1[1] -= cu->tb[i].h; + glVertex3fv(vec1); + vec1[0] -= cu->tb[i].w; + glVertex3fv(vec1); + vec1[1] += cu->tb[i].h; + glVertex3fv(vec1); + glEnd(); + } + } + setlinestyle(0); + + + if (getselection(&selstart, &selend) && selboxes) { + float selboxw; + + cpack(0xffffff); + set_inverted_drawing(1); + for (i=0; i<(selend-selstart+1); i++) { + SelBox *sb = &(selboxes[i]); + + if (i<(selend-selstart)) { + if (selboxes[i+1].y == sb->y) + selboxw= selboxes[i+1].x - sb->x; + else + selboxw= sb->w; + } + else { + selboxw= sb->w; + } + glBegin(GL_QUADS); + glVertex3f(sb->x, sb->y, 0.001); + glVertex3f(sb->x+selboxw, sb->y, 0.001); + glVertex3f(sb->x+selboxw, sb->y+sb->h, 0.001); + glVertex3f(sb->x, sb->y+sb->h, 0.001); + glEnd(); + } + set_inverted_drawing(0); + } + } + else if(dt==OB_BOUNDBOX) + draw_bounding_volume(ob); + else if(boundbox_clip(v3d, ob->obmat, cu->bb)) + empty_object= drawDispList(scene, v3d, base, dt); + + break; + case OB_CURVE: + case OB_SURF: + cu= ob->data; + /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */ + if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0); + + if(ob==G.obedit) { + drawnurb(scene, v3d, base, editNurb.first, dt); + } + else if(dt==OB_BOUNDBOX) + draw_bounding_volume(ob); + else if(boundbox_clip(v3d, ob->obmat, cu->bb)) { + empty_object= drawDispList(scene, v3d, base, dt); + + if(cu->path) + curve_draw_speed(scene, ob); + } + break; + case OB_MBALL: + if(ob==G.obedit) + drawmball(C, scene, v3d, base, dt); + else if(dt==OB_BOUNDBOX) + draw_bounding_volume(ob); + else + empty_object= drawmball(C, scene, v3d, base, dt); + break; + case OB_EMPTY: + drawaxes(ob->empty_drawsize, flag, ob->empty_drawtype); + break; + case OB_LAMP: + drawlamp(C, scene, v3d, ob); + if(dtx || (base->flag & SELECT)) wmMultMatrix(CTX_wm_window(C), ob->obmat); + break; + case OB_CAMERA: + drawcamera(C, scene, v3d, ob, flag); + break; + case OB_LATTICE: + drawlattice(v3d, ob); + break; + case OB_ARMATURE: + if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material + empty_object= draw_armature(base, dt, flag); + if(dt>OB_WIRE) GPU_disable_material(); + break; + default: + drawaxes(1.0, flag, OB_ARROWS); + } + if(ob->pd && ob->pd->forcefield) draw_forcefield(C, scene, ob); + + /* code for new particle system */ + if( (warning_recursive==0) && + (ob->particlesystem.first) && + (flag & DRAW_PICKING)==0 && + (ob!=G.obedit) + ) { + ParticleSystem *psys; + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ + glDepthMask(GL_FALSE); + + for(psys=ob->particlesystem.first; psys; psys=psys->next) + draw_new_particle_system(C, v3d, base, psys, dt); + + if(G.f & G_PARTICLEEDIT && ob==OBACT) { + psys= NULL; // XXX PE_get_current(ob); + if(psys && !G.obedit && psys_in_edit_mode(psys)) + draw_particle_edit(C, scene, v3d, ob, psys, dt); + } + glDepthMask(GL_TRUE); + if(col) cpack(col); + } + + { + bConstraint *con; + for(con=ob->constraints.first; con; con= con->next) + { + if(con->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) + { + bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)con->data; + if(data->flag&CONSTRAINT_DRAW_PIVOT) + drawRBpivot(data); + } + } + } + + /* draw extra: after normal draw because of makeDispList */ + if(dtx && !(G.f & (G_RENDER_OGL|G_RENDER_SHADOW))) { + if(dtx & OB_AXIS) { + drawaxes(1.0f, flag, OB_ARROWS); + } + if(dtx & OB_BOUNDBOX) draw_bounding_volume(ob); + if(dtx & OB_TEXSPACE) drawtexspace(ob); + if(dtx & OB_DRAWNAME) { + /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */ + /* but, we also dont draw names for sets or duplicators */ + if(flag == 0) { + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + glRasterPos3f(0.0, 0.0, 0.0); + + BMF_DrawString(G.font, " "); + BMF_DrawString(G.font, ob->id.name+2); + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + } + /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/ + if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) drawWireExtra(scene, v3d, ob); + } + + if(dt<OB_SHADED) { + if((ob->gameflag & OB_DYNAMIC) || + ((ob->gameflag & OB_BOUNDS) && (ob->boundtype == OB_BOUND_SPHERE))) { + float tmat[4][4], imat[4][4], vec[3]; + + vec[0]= vec[1]= vec[2]= 0.0; + wmGetMatrix(CTX_wm_window(C), tmat); + Mat4Invert(imat, tmat); + + setlinestyle(2); + drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat); + setlinestyle(0); + } + } + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + + if(zbufoff) glDisable(GL_DEPTH_TEST); + + if(warning_recursive) return; + if(base->flag & (OB_FROMDUPLI|OB_RADIO)) return; + if(G.f & G_RENDER_SHADOW) return; + + /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */ + if(ob!=OBACT || (G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) { + int do_draw_center= -1; /* defines below are zero or positive... */ + + if((scene->basact)==base) + do_draw_center= ACTIVE; + else if(base->flag & SELECT) + do_draw_center= SELECT; + else if(empty_object || (v3d->flag & V3D_DRAW_CENTERS)) + do_draw_center= DESELECT; + + if(do_draw_center != -1) { + if(flag & DRAW_PICKING) { + /* draw a single point for opengl selection */ + glBegin(GL_POINTS); + glVertex3fv(ob->obmat[3]); + glEnd(); + } + else if((flag & DRAW_CONSTCOLOR)==0) { + /* we don't draw centers for duplicators and sets */ + drawcentercircle(v3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us>1); + } + } + } + + /* not for sets, duplicators or picking */ + if(flag==0 && (!(v3d->flag & V3D_HIDE_HELPLINES))) { + ListBase *list; + + /* draw hook center and offset line */ + if(ob!=G.obedit) draw_hooks(ob); + + /* help lines and so */ + if(ob!=G.obedit && ob->parent && (ob->parent->lay & v3d->lay)) { + setlinestyle(3); + glBegin(GL_LINES); + glVertex3fv(ob->obmat[3]); + glVertex3fv(ob->orig); + glEnd(); + setlinestyle(0); + } + + /* Drawing the constraint lines */ + list = &ob->constraints; + if (list) { + bConstraint *curcon; + bConstraintOb *cob; + char col[4], col2[4]; + + UI_GetThemeColor3ubv(TH_GRID, col); + make_axis_color(col, col2, 'z'); + glColor3ubv((GLubyte *)col2); + + cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + + for (curcon = list->first; curcon; curcon=curcon->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) { + cti->get_constraint_targets(curcon, &targets); + + for (ct= targets.first; ct; ct= ct->next) { + /* calculate target's matrix */ + if (cti->get_target_matrix) + cti->get_target_matrix(curcon, cob, ct, bsystem_time(ob, (float)(scene->r.cfra), give_timeoffset(ob))); + else + Mat4One(ct->matrix); + + setlinestyle(3); + glBegin(GL_LINES); + glVertex3fv(ct->matrix[3]); + glVertex3fv(ob->obmat[3]); + glEnd(); + setlinestyle(0); + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(curcon, &targets, 1); + } + } + + constraints_clear_evalob(cob); + } + } + + free_old_images(); +} + +void draw_object_ext(const bContext *C, ARegion *ar, View3D *v3d, Scene *scene, Base *base) +{ + + if(v3d==NULL || base==NULL) return; + + if(v3d->drawtype > OB_WIRE) { + v3d->zbuf= 1; + glEnable(GL_DEPTH_TEST); + } + + G.f |= G_DRAW_EXT; + + glDrawBuffer(GL_FRONT); +// XXX persp(PERSP_VIEW); + + if(v3d->flag & V3D_CLIPPING) + view3d_set_clipping(v3d); + + draw_object(C, scene, ar, v3d, base, 0); + + if(v3d->flag & V3D_CLIPPING) + view3d_clr_clipping(); + + G.f &= ~G_DRAW_EXT; + + bglFlush(); /* reveil frontbuffer drawing */ + glDrawBuffer(GL_BACK); + + if(v3d->zbuf) { + v3d->zbuf= 0; + glDisable(GL_DEPTH_TEST); + } +// XXX ar->win_swap= WIN_FRONT_OK; +} + +/* ***************** BACKBUF SEL (BBS) ********* */ + +static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) +{ + int offset = (intptr_t) userData; + EditVert *eve = EM_get_vert_for_index(index); + + if (eve->h==0) { + WM_set_framebuffer_index_color(offset+index); + bglVertex3fv(co); + } +} +static int bbs_mesh_verts(DerivedMesh *dm, int offset) +{ + glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); + bglBegin(GL_POINTS); + dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset); + bglEnd(); + glPointSize(1.0); + + return offset + G.totvert; +} + +static int bbs_mesh_wire__setDrawOptions(void *userData, int index) +{ + int offset = (intptr_t) userData; + EditEdge *eed = EM_get_edge_for_index(index); + + if (eed->h==0) { + WM_set_framebuffer_index_color(offset+index); + return 1; + } else { + return 0; + } +} +static int bbs_mesh_wire(DerivedMesh *dm, int offset) +{ + dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); + + return offset + G.totedge; +} + +static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) +{ + if (EM_get_face_for_index(index)->h==0) { + if (userData) { + WM_set_framebuffer_index_color(index+1); + } + return 1; + } else { + return 0; + } +} + +static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *no) +{ + EditFace *efa = EM_get_face_for_index(index); + + if (efa->h==0 && efa->fgonf!=EM_FGON) { + WM_set_framebuffer_index_color(index+1); + + bglVertex3fv(cent); + } +} + +/* two options, facecolors or black */ +static int bbs_mesh_solid_EM(Scene *scene, View3D *v3d, DerivedMesh *dm, int facecol) +{ + cpack(0); + + if (facecol) { + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0); + + if( CHECK_OB_DRAWFACEDOT(scene, v3d, G.obedit->dt) ) { + glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); + + bglBegin(GL_POINTS); + dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL); + bglEnd(); + } + + return 1+G.totface; + } else { + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0); + return 1; + } +} + +static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmooth_r) +{ + Mesh *me = userData; + + if (!(me->mface[index].flag&ME_HIDE)) { + WM_set_framebuffer_index_color(index+1); + return 1; + } else { + return 0; + } +} + +/* TODO remove this - since face select mode now only works with painting */ +static void bbs_mesh_solid(Object *ob) +{ + DerivedMesh *dm = mesh_get_derived_final(ob, get_viewedit_datamask()); + Mesh *me = (Mesh*)ob->data; + + glColor3ub(0, 0, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0); + + dm->release(dm); +} + +void draw_object_backbufsel(const bContext *C, Scene *scene, View3D *v3d, Object *ob) +{ + + wmMultMatrix(CTX_wm_window(C), ob->obmat); + + glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + + switch( ob->type) { + case OB_MESH: + if(ob==G.obedit) { + DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + EM_init_index_arrays(1, 1, 1); + + em_solidoffs= bbs_mesh_solid_EM(scene, v3d, dm, scene->selectmode & SCE_SELECT_FACE); + + bglPolygonOffset(1.0); + + // we draw edges always, for loop (select) tools + em_wireoffs= bbs_mesh_wire(dm, em_solidoffs); + + // we draw verts if vert select mode or if in transform (for snap). + if(scene->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) + em_vertoffs= bbs_mesh_verts(dm, em_wireoffs); + else em_vertoffs= em_wireoffs; + + bglPolygonOffset(0.0); + + dm->release(dm); + + EM_free_index_arrays(); + } + else bbs_mesh_solid(ob); + + break; + case OB_CURVE: + case OB_SURF: + break; + } + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); +} + + +/* ************* draw object instances for bones, for example ****************** */ +/* assumes all matrices/etc set OK */ + +/* helper function for drawing object instances - meshes */ +static void draw_object_mesh_instance(Scene *scene, View3D *v3d, Object *ob, int dt, int outline) +{ + DerivedMesh *dm=NULL, *edm=NULL; + int glsl; + + if(G.obedit && ob->data==G.obedit->data) + edm= editmesh_get_derived_base(); + else + dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + + if(dt<=OB_WIRE) { + if(dm) + dm->drawEdges(dm, 1); + else if(edm) + edm->drawEdges(edm, 1); + } + else { + if(outline) + draw_mesh_object_outline(v3d, ob, dm?dm:edm); + + if(dm) { + glsl = draw_glsl_material(scene, ob, v3d, dt); + GPU_set_object_materials(scene, ob, glsl, NULL); + } + else { + glEnable(GL_COLOR_MATERIAL); + UI_ThemeColor(TH_BONE_SOLID); + glDisable(GL_COLOR_MATERIAL); + } + + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); + glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); + glEnable(GL_LIGHTING); + + if(dm) { + dm->drawFacesSolid(dm, GPU_enable_material); + GPU_disable_material(); + } + else if(edm) + edm->drawMappedFaces(edm, NULL, NULL, 0); + + glDisable(GL_LIGHTING); + } + + if(edm) edm->release(edm); + if(dm) dm->release(dm); +} + +void draw_object_instance(Scene *scene, View3D *v3d, Object *ob, int dt, int outline) +{ + if (ob == NULL) + return; + + switch (ob->type) { + case OB_MESH: + draw_object_mesh_instance(scene, v3d, ob, dt, outline); + break; + case OB_EMPTY: + drawaxes(ob->empty_drawsize, 0, ob->empty_drawtype); + break; + } +} diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 712a69be77b..d03681d6a59 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -33,6 +33,7 @@ #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_camera_types.h" +#include "DNA_group_types.h" #include "DNA_key_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" @@ -72,12 +73,16 @@ #include "ED_screen.h" #include "ED_util.h" +#include "ED_types.h" #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" +#include "GPU_draw.h" +#include "GPU_material.h" + #include "view3d_intern.h" // own include @@ -1145,6 +1150,178 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) // XXX areawinset(ar->win); // restore viewport / scissor } +/* ****************** View3d afterdraw *************** */ + +typedef struct View3DAfter { + struct View3DAfter *next, *prev; + struct Base *base; + int type, flag; +} View3DAfter; + +/* temp storage of Objects that need to be drawn as last */ +void add_view3d_after(View3D *v3d, Base *base, int type, int flag) +{ + View3DAfter *v3da= MEM_callocN(sizeof(View3DAfter), "View 3d after"); + + BLI_addtail(&v3d->afterdraw, v3da); + v3da->base= base; + v3da->type= type; + v3da->flag= flag; +} + +/* clears zbuffer and draws it over */ +static void view3d_draw_xray(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, int clear) +{ + View3DAfter *v3da, *next; + int doit= 0; + + for(v3da= v3d->afterdraw.first; v3da; v3da= v3da->next) + if(v3da->type==V3D_XRAY) doit= 1; + + if(doit) { + if(clear && v3d->zbuf) glClear(GL_DEPTH_BUFFER_BIT); + v3d->xray= TRUE; + + for(v3da= v3d->afterdraw.first; v3da; v3da= next) { + next= v3da->next; + if(v3da->type==V3D_XRAY) { + draw_object(C, scene, ar, v3d, v3da->base, v3da->flag); + BLI_remlink(&v3d->afterdraw, v3da); + MEM_freeN(v3da); + } + } + v3d->xray= FALSE; + } +} + +/* disables write in zbuffer and draws it over */ +static void view3d_draw_transp(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d) +{ + View3DAfter *v3da, *next; + + glDepthMask(0); + v3d->transp= TRUE; + + for(v3da= v3d->afterdraw.first; v3da; v3da= next) { + next= v3da->next; + if(v3da->type==V3D_TRANSP) { + draw_object(C, scene, ar, v3d, v3da->base, v3da->flag); + BLI_remlink(&v3d->afterdraw, v3da); + MEM_freeN(v3da); + } + } + v3d->transp= FALSE; + + glDepthMask(1); + +} + +/* *********************** */ + +/* + In most cases call draw_dupli_objects, + draw_dupli_objects_color was added because when drawing set dupli's + we need to force the color + */ +static void draw_dupli_objects_color(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, Base *base, int color) +{ + ListBase *lb; + DupliObject *dob; + Base tbase; + BoundBox *bb= NULL; + GLuint displist=0; + short transflag, use_displist= -1; /* -1 is initialize */ + char dt, dtx; + + if (base->object->restrictflag & OB_RESTRICT_VIEW) return; + + tbase.flag= OB_FROMDUPLI|base->flag; + lb= object_duplilist(scene, base->object); + + for(dob= lb->first; dob; dob= dob->next) { + if(dob->no_draw); + else { + tbase.object= dob->ob; + + /* extra service: draw the duplicator in drawtype of parent */ + /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ + dt= tbase.object->dt; tbase.object->dt= MIN2(tbase.object->dt, base->object->dt); + dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx; + + /* negative scale flag has to propagate */ + transflag= tbase.object->transflag; + if(base->object->transflag & OB_NEG_SCALE) + tbase.object->transflag ^= OB_NEG_SCALE; + + UI_ThemeColorBlend(color, TH_BACK, 0.5); + + /* generate displist, test for new object */ + if(use_displist==1 && dob->prev && dob->prev->ob!=dob->ob) { + use_displist= -1; + glDeleteLists(displist, 1); + } + /* generate displist */ + if(use_displist == -1) { + + /* lamp drawing messes with matrices, could be handled smarter... but this works */ + if(dob->ob->type==OB_LAMP || dob->type==OB_DUPLIGROUP) + use_displist= 0; + else { + /* disable boundbox check for list creation */ + object_boundbox_flag(dob->ob, OB_BB_DISABLED, 1); + /* need this for next part of code */ + bb= object_get_boundbox(dob->ob); + + Mat4One(dob->ob->obmat); /* obmat gets restored */ + + displist= glGenLists(1); + glNewList(displist, GL_COMPILE); + draw_object(C, scene, ar, v3d, &tbase, DRAW_CONSTCOLOR); + glEndList(); + + use_displist= 1; + object_boundbox_flag(dob->ob, OB_BB_DISABLED, 0); + } + } + if(use_displist) { + wmMultMatrix(CTX_wm_window(C), dob->mat); + if(boundbox_clip(v3d, dob->mat, bb)) + glCallList(displist); + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); + } + else { + Mat4CpyMat4(dob->ob->obmat, dob->mat); + draw_object(C, scene, ar, v3d, &tbase, DRAW_CONSTCOLOR); + } + + tbase.object->dt= dt; + tbase.object->dtx= dtx; + tbase.object->transflag= transflag; + } + } + + /* Transp afterdraw disabled, afterdraw only stores base pointers, and duplis can be same obj */ + + free_object_duplilist(lb); /* does restore */ + + if(use_displist) + glDeleteLists(displist, 1); +} + +static void draw_dupli_objects(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, Base *base) +{ + /* define the color here so draw_dupli_objects_color can be called + * from the set loop */ + + int color= (base->flag & SELECT)?TH_SELECT:TH_WIRE; + /* debug */ + if(base->object->dup_group && base->object->dup_group->id.us<1) + color= TH_REDALERT; + + draw_dupli_objects_color(C, scene, ar, v3d, base, color); +} + + void view3d_update_depths(ARegion *ar, View3D *v3d) { /* Create storage for, and, if necessary, copy depth buffer */ @@ -1174,7 +1351,7 @@ void view3d_update_depths(ARegion *ar, View3D *v3d) } /* Enable sculpting in wireframe mode by drawing sculpt object only to the depth buffer */ -static void draw_sculpt_depths(Scene *scene, View3D *v3d) +static void draw_sculpt_depths(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d) { Object *ob = OBACT; @@ -1193,7 +1370,7 @@ static void draw_sculpt_depths(Scene *scene, View3D *v3d) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glEnable(GL_DEPTH_TEST); -// XXX draw_object(BASACT, 0); + draw_object(C, scene, ar, v3d, BASACT, 0); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); if(!depth_on) glDisable(GL_DEPTH_TEST); @@ -1204,6 +1381,185 @@ static void draw_sculpt_depths(Scene *scene, View3D *v3d) } } +void draw_depth(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, int (* func)(void *)) +{ + Base *base; + Scene *sce; + short zbuf, flag; + float glalphaclip; + /* temp set drawtype to solid */ + + /* Setting these temporarily is not nice */ + zbuf = v3d->zbuf; + flag = v3d->flag; + glalphaclip = U.glalphaclip; + + U.glalphaclip = 0.5; /* not that nice but means we wont zoom into billboards */ + v3d->flag &= ~V3D_SELECT_OUTLINE; + + setwinmatrixview3d(CTX_wm_window(C), v3d, ar->winx, ar->winy, NULL); /* 0= no pick rect */ + setviewmatrixview3d(v3d); /* note: calls where_is_object for camera... */ + + Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat); + Mat4Invert(v3d->persinv, v3d->persmat); + Mat4Invert(v3d->viewinv, v3d->viewmat); + + glClear(GL_DEPTH_BUFFER_BIT); + + wmLoadMatrix(CTX_wm_window(C), v3d->viewmat); +// persp(PERSP_STORE); // store correct view for persp(PERSP_VIEW) calls + + if(v3d->flag & V3D_CLIPPING) { + view3d_set_clipping(v3d); + } + + v3d->zbuf= TRUE; + glEnable(GL_DEPTH_TEST); + + /* draw set first */ + if(scene->set) { + for(SETLOOPER(scene->set, base)) { + if(v3d->lay & base->lay) { + if (func == NULL || func(base)) { + draw_object(C, scene, ar, v3d, base, 0); + if(base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(C, scene, ar, v3d, base, TH_WIRE); + } + } + } + } + } + + for(base= scene->base.first; base; base= base->next) { + if(v3d->lay & base->lay) { + if (func == NULL || func(base)) { + /* dupli drawing */ + if(base->object->transflag & OB_DUPLI) { + draw_dupli_objects(C, scene, ar, v3d, base); + } + draw_object(C, scene, ar, v3d, base, 0); + } + } + } + + /* this isnt that nice, draw xray objects as if they are normal */ + if (v3d->afterdraw.first) { + View3DAfter *v3da, *next; + int num = 0; + v3d->xray= TRUE; + + glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ + for(v3da= v3d->afterdraw.first; v3da; v3da= next) { + next= v3da->next; + if(v3da->type==V3D_XRAY) { + draw_object(C, scene, ar, v3d, v3da->base, 0); + num++; + } + /* dont remove this time */ + } + v3d->xray= FALSE; + + glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ + for(v3da= v3d->afterdraw.first; v3da; v3da= next) { + next= v3da->next; + if(v3da->type==V3D_XRAY) { + v3d->xray= TRUE; v3d->transp= FALSE; + } else if (v3da->type==V3D_TRANSP) { + v3d->xray= FALSE; v3d->transp= TRUE; + } + + draw_object(C, scene, ar, v3d, v3da->base, 0); /* Draw Xray or Transp objects normally */ + BLI_remlink(&v3d->afterdraw, v3da); + MEM_freeN(v3da); + } + v3d->xray= FALSE; + v3d->transp= FALSE; + } + + v3d->zbuf = zbuf; + U.glalphaclip = glalphaclip; + v3d->flag = flag; +} + +typedef struct View3DShadow { + struct View3DShadow *next, *prev; + GPULamp *lamp; +} View3DShadow; + +static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object *par, float obmat[][4], ListBase *shadows) +{ + GPULamp *lamp; + View3DShadow *shadow; + + lamp = GPU_lamp_from_blender(scene, ob, par); + + if(lamp) { + GPU_lamp_update(lamp, ob->lay, obmat); + + if((ob->lay & v3d->lay) && GPU_lamp_has_shadow_buffer(lamp)) { + shadow= MEM_callocN(sizeof(View3DShadow), "View3DShadow"); + shadow->lamp = lamp; + BLI_addtail(shadows, shadow); + } + } +} + +static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d) +{ + ListBase shadows; + View3DShadow *shadow; + Scene *sce; + Base *base; + Object *ob; + + shadows.first= shadows.last= NULL; + + /* update lamp transform and gather shadow lamps */ + for(SETLOOPER(scene, base)) { + ob= base->object; + + if(ob->type == OB_LAMP) + gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, &shadows); + + if (ob->transflag & OB_DUPLI) { + DupliObject *dob; + ListBase *lb = object_duplilist(scene, ob); + + for(dob=lb->first; dob; dob=dob->next) + if(dob->ob->type==OB_LAMP) + gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, &shadows); + + free_object_duplilist(lb); + } + } + + /* render shadows after updating all lamps, nested object_duplilist + * don't work correct since it's replacing object matrices */ + for(shadow=shadows.first; shadow; shadow=shadow->next) { + /* this needs to be done better .. */ + float viewmat[4][4], winmat[4][4]; + int drawtype, lay, winsize, flag2; + + drawtype= v3d->drawtype; + lay= v3d->lay; + flag2= v3d->flag2 & V3D_SOLID_TEX; + + v3d->drawtype = OB_SOLID; + v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); + v3d->flag2 &= ~V3D_SOLID_TEX; + + GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); +// XXX drawview3d_render(v3d, viewmat, winsize, winsize, winmat, 1); + GPU_lamp_shadow_buffer_unbind(shadow->lamp); + + v3d->drawtype= drawtype; + v3d->lay= lay; + v3d->flag2 |= flag2; + } + + BLI_freelistN(&shadows); +} + void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) { @@ -1228,8 +1584,8 @@ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) } /* shadow buffers, before we setup matrices */ -// if(draw_glsl_material(NULL, v3d->drawtype)) -// gpu_update_lamps_shadows(scene, v3d); + if(draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) + gpu_update_lamps_shadows(scene, v3d); setwinmatrixview3d(CTX_wm_window(C), v3d, ar->winx, ar->winy, NULL); /* 0= no pick rect */ setviewmatrixview3d(v3d); /* note: calls where_is_object for camera... */ @@ -1319,10 +1675,10 @@ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) if(v3d->lay & base->lay) { UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); -// XXX draw_object(base, DRAW_CONSTCOLOR|DRAW_SCENESET); + draw_object(C, scene, ar, v3d, base, DRAW_CONSTCOLOR|DRAW_SCENESET); if(base->object->transflag & OB_DUPLI) { -// XXX draw_dupli_objects_color(v3d, base, TH_WIRE); + draw_dupli_objects_color(C, scene, ar, v3d, base, TH_WIRE); } } } @@ -1336,10 +1692,11 @@ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) /* dupli drawing */ if(base->object->transflag & OB_DUPLI) { -// XXX draw_dupli_objects(v3d, base); + draw_dupli_objects(C, scene, ar, v3d, base); } if((base->flag & SELECT)==0) { -// XXX if(base->object!=G.obedit) draw_object(base, 0); + if(base->object!=G.obedit) + draw_object(C, scene, ar, v3d, base, 0); } } } @@ -1352,14 +1709,14 @@ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) /* draw selected and editmode */ for(base= scene->base.first; base; base= base->next) { if(v3d->lay & base->lay) { -// if (base->object==G.obedit || ( base->flag & SELECT) ) -// XXX draw_object(base, 0); + if (base->object==G.obedit || ( base->flag & SELECT) ) + draw_object(C, scene, ar, v3d, base, 0); } } if(!retopo && sculptparticle && !(obact && (obact->dtx & OB_DRAWXRAY))) { if(G.f & G_SCULPTMODE) - draw_sculpt_depths(scene, v3d); + draw_sculpt_depths(C, scene, ar, v3d); view3d_update_depths(ar, v3d); } @@ -1375,12 +1732,12 @@ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d) // if(scene->radio) RAD_drawall(v3d->drawtype>=OB_SOLID); /* Transp and X-ray afterdraw stuff */ -// view3d_draw_transp(v3d); -// view3d_draw_xray(v3d, 1); // clears zbuffer if it is used! + view3d_draw_transp(C, scene, ar, v3d); + view3d_draw_xray(C, scene, ar, v3d, 1); // clears zbuffer if it is used! if(!retopo && sculptparticle && (obact && (OBACT->dtx & OB_DRAWXRAY))) { if(G.f & G_SCULPTMODE) - draw_sculpt_depths(scene, v3d); + draw_sculpt_depths(C, scene, ar, v3d); view3d_update_depths(ar, v3d); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c new file mode 100644 index 00000000000..5ac774afadb --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -0,0 +1,1086 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "DNA_action_types.h" +#include "DNA_camera_types.h" +#include "DNA_lamp_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_global.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "RE_pipeline.h" // make_stars + +#include "BIF_gl.h" +#include "BIF_retopo.h" + +#include "WM_api.h" + +#include "ED_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "PIL_time.h" /* smoothview */ + +#include "view3d_intern.h" // own include + +/* ********************** view3d_edit: view manipulations ********************* */ + +#define TRACKBALLSIZE (1.1) + +/* the central math in this function was copied from trackball.cpp, sample code from the + Developers Toolbox series by SGI. */ + +/* trackball: better one than a full spherical solution */ + +void calctrackballvecfirst(rcti *area, short *mval, float *vec) +{ + float x, y, radius, d, z, t; + + radius= TRACKBALLSIZE; + + /* normalize x and y */ + x= (area->xmax + area->xmin)/2 -mval[0]; + x/= (float)((area->xmax - area->xmin)/2); + y= (area->ymax + area->ymin)/2 -mval[1]; + y/= (float)((area->ymax - area->ymin)/2); + + d = sqrt(x*x + y*y); + if (d < radius*M_SQRT1_2) /* Inside sphere */ + z = sqrt(radius*radius - d*d); + else + { /* On hyperbola */ + t = radius / M_SQRT2; + z = t*t / d; + } + + vec[0]= x; + vec[1]= y; + vec[2]= -z; /* yah yah! */ + + if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) { + vec[0]= 0.0; + vec[1]= 0.0; + if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0; + } + else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) { + vec[0]= 0.0; + vec[2]= 0.0; + if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0; + } + else { + vec[1]= 0.0; + vec[2]= 0.0; + if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0; + } +} + +void calctrackballvec(rcti *area, short *mval, float *vec) +{ + float x, y, radius, d, z, t; + + radius= TRACKBALLSIZE; + + /* x en y normalizeren */ + x= (area->xmax + area->xmin)/2 -mval[0]; + x/= (float)((area->xmax - area->xmin)/4); + y= (area->ymax + area->ymin)/2 -mval[1]; + y/= (float)((area->ymax - area->ymin)/2); + + d = sqrt(x*x + y*y); + if (d < radius*M_SQRT1_2) /* Inside sphere */ + z = sqrt(radius*radius - d*d); + else + { /* On hyperbola */ + t = radius / M_SQRT2; + z = t*t / d; + } + + vec[0]= x; + vec[1]= y; + vec[2]= -z; /* yah yah! */ + +} + + +// ndof scaling will be moved to user setting. +// In the mean time this is just a place holder. + +// Note: scaling in the plugin and ghostwinlay.c +// should be removed. With driver default setting, +// each axis returns approx. +-200 max deflection. + +// The values I selected are based on the older +// polling i/f. With event i/f, the sensistivity +// can be increased for improved response from +// small deflections of the device input. + + +// lukep notes : i disagree on the range. +// the normal 3Dconnection driver give +/-400 +// on defaut range in other applications +// and up to +/- 1000 if set to maximum +// because i remove the scaling by delta, +// which was a bad idea as it depend of the system +// speed and os, i changed the scaling values, but +// those are still not ok + + +float ndof_axis_scale[6] = { + +0.01, // Tx + +0.01, // Tz + +0.01, // Ty + +0.0015, // Rx + +0.0015, // Rz + +0.0015 // Ry +}; + +void filterNDOFvalues(float *sbval) +{ + int i=0; + float max = 0.0; + + for (i =0; i<6;i++) + if (fabs(sbval[i]) > max) + max = fabs(sbval[i]); + for (i =0; i<6;i++) + if (fabs(sbval[i]) != max ) + sbval[i]=0.0; +} + +// statics for controlling v3d->dist corrections. +// viewmoveNDOF zeros and adjusts v3d->ofs. +// viewmove restores based on dz_flag state. + +int dz_flag = 0; +float m_dist; + +void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode) +{ + int i; + float phi; + float dval[7]; + // static fval[6] for low pass filter; device input vector is dval[6] + static float fval[6]; + float tvec[3],rvec[3]; + float q1[4]; + float mat[3][3]; + float upvec[3]; + + + /*---------------------------------------------------- + * sometimes this routine is called from headerbuttons + * viewmove needs to refresh the screen + */ +// XXX areawinset(ar->win); + + + // fetch the current state of the ndof device +// XXX getndof(dval); + + if (v3d->ndoffilter) + filterNDOFvalues(fval); + + // Scale input values + +// if(dval[6] == 0) return; // guard against divide by zero + + for(i=0;i<6;i++) { + + // user scaling + dval[i] = dval[i] * ndof_axis_scale[i]; + } + + + // low pass filter with zero crossing reset + + for(i=0;i<6;i++) { + if((dval[i] * fval[i]) >= 0) + dval[i] = (fval[i] * 15 + dval[i]) / 16; + else + fval[i] = 0; + } + + + // force perspective mode. This is a hack and is + // incomplete. It doesn't actually effect the view + // until the first draw and doesn't update the menu + // to reflect persp mode. + + v3d->persp = V3D_PERSP; + + + // Correct the distance jump if v3d->dist != 0 + + // This is due to a side effect of the original + // mouse view rotation code. The rotation point is + // set a distance in front of the viewport to + // make rotating with the mouse look better. + // The distance effect is written at a low level + // in the view management instead of the mouse + // view function. This means that all other view + // movement devices must subtract this from their + // view transformations. + + if(v3d->dist != 0.0) { + dz_flag = 1; + m_dist = v3d->dist; + upvec[0] = upvec[1] = 0; + upvec[2] = v3d->dist; + Mat3CpyMat4(mat, v3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecSubf(v3d->ofs, v3d->ofs, upvec); + v3d->dist = 0.0; + } + + + // Apply rotation + // Rotations feel relatively faster than translations only in fly mode, so + // we have no choice but to fix that here (not in the plugins) + rvec[0] = -0.5 * dval[3]; + rvec[1] = -0.5 * dval[4]; + rvec[2] = -0.5 * dval[5]; + + // rotate device x and y by view z + + Mat3CpyMat4(mat, v3d->viewinv); + mat[2][2] = 0.0f; + Mat3MulVecfl(mat, rvec); + + // rotate the view + + phi = Normalize(rvec); + if(phi != 0) { + VecRotToQuat(rvec,phi,q1); + QuatMul(v3d->viewquat, v3d->viewquat, q1); + } + + + // Apply translation + + tvec[0] = dval[0]; + tvec[1] = dval[1]; + tvec[2] = -dval[2]; + + // the next three lines rotate the x and y translation coordinates + // by the current z axis angle + + Mat3CpyMat4(mat, v3d->viewinv); + mat[2][2] = 0.0f; + Mat3MulVecfl(mat, tvec); + + // translate the view + + VecSubf(v3d->ofs, v3d->ofs, tvec); + + + /*---------------------------------------------------- + * refresh the screen XXX + */ + + // update render preview window + +// XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT); +} + +/* Zooms in on a border drawn by the user */ +static int view_autodist(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist ) +{ + rcti rect; + /* ZBuffer depth vars */ + bglMats mats; + float depth, depth_close= MAXFLOAT; + int had_depth = 0; + double cent[2], p[3]; + int xs, ys; + +// XXX getmouseco_areawin(mval); + +// XXX persp(PERSP_VIEW); + + rect.xmax = mval[0] + 4; + rect.ymax = mval[1] + 4; + + rect.xmin = mval[0] - 4; + rect.ymin = mval[1] - 4; + + /* Get Z Depths, needed for perspective, nice for ortho */ + bgl_get_mats(&mats); + draw_depth(C, scene, ar, v3d, NULL); + + /* force updating */ + if (v3d->depths) { + had_depth = 1; + v3d->depths->damaged = 1; + } + + view3d_update_depths(ar, v3d); + + /* Constrain rect to depth bounds */ + if (rect.xmin < 0) rect.xmin = 0; + if (rect.ymin < 0) rect.ymin = 0; + if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1; + if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1; + + /* Find the closest Z pixel */ + for (xs=rect.xmin; xs < rect.xmax; xs++) { + for (ys=rect.ymin; ys < rect.ymax; ys++) { + depth= v3d->depths->depths[ys*v3d->depths->w+xs]; + if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) { + if (depth_close > depth) { + depth_close = depth; + } + } + } + } + + if (depth_close==MAXFLOAT) + return 0; + + if (had_depth==0) { + MEM_freeN(v3d->depths->depths); + v3d->depths->depths = NULL; + } + v3d->depths->damaged = 1; + + cent[0] = (double)mval[0]; + cent[1] = (double)mval[1]; + + if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) + return 0; + + mouse_worldloc[0] = (float)p[0]; + mouse_worldloc[1] = (float)p[1]; + mouse_worldloc[2] = (float)p[2]; + return 1; +} + +static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, short *mouseloc) +{ + if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + short vb[2]; + float dvec[3]; + float tvec[3]; + float tpos[3]; + float new_dist; + + /* find the current window width and height */ + vb[0] = ar->winx; + vb[1] = ar->winy; + + tpos[0] = -v3d->ofs[0]; + tpos[1] = -v3d->ofs[1]; + tpos[2] = -v3d->ofs[2]; + + /* Project cursor position into 3D space */ + initgrabz(v3d, tpos[0], tpos[1], tpos[2]); + window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2); + + /* Calculate view target position for dolly */ + tvec[0] = -(tpos[0] + dvec[0]); + tvec[1] = -(tpos[1] + dvec[1]); + tvec[2] = -(tpos[2] + dvec[2]); + + /* Offset to target position and dolly */ + new_dist = v3d->dist * dfac; + + VECCOPY(v3d->ofs, tvec); + v3d->dist = new_dist; + + /* Calculate final offset */ + dvec[0] = tvec[0] + dvec[0] * dfac; + dvec[1] = tvec[1] + dvec[1] * dfac; + dvec[2] = tvec[2] + dvec[2] * dfac; + + VECCOPY(v3d->ofs, dvec); + } else { + v3d->dist *= dfac; + } +} + + +#define COS45 0.70710678118654746 +#define SIN45 COS45 + +void viewmove(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, int mode) +{ + static float lastofs[3] = {0,0,0}; + Object *ob = OBACT; + float firstvec[3], newvec[3], dvec[3]; + float reverse, oldquat[4], q1[4], si, phi, dist0; + float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f}; + int firsttime=1; + short mvalball[2], mval[2], mvalo[2], mval_area[2], mvali[2]; + short use_sel = 0; + short preview3d_event= 1; + + // locals for dist correction + float mat[3][3]; + float upvec[3]; + + /* 3D window may not be defined */ + if( !v3d ) { + fprintf( stderr, "v3d == NULL in viewmove()\n" ); + return; + } + + // dist correction from other movement devices + if((dz_flag)||v3d->dist==0) { + dz_flag = 0; + v3d->dist = m_dist; + upvec[0] = upvec[1] = 0; + upvec[2] = v3d->dist; + Mat3CpyMat4(mat, v3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecAddf(v3d->ofs, v3d->ofs, upvec); + } + + /* sometimes this routine is called from headerbuttons */ + +// XXX areawinset(ar->win); + + QUATCOPY(oldquat, v3d->viewquat); + +// XXX getmouseco_areawin(mval_area); /* for zoom to mouse loc */ +// XXX getmouseco_sc(mvali); /* work with screen coordinates because of trackball function */ + mvalball[0]= mvalo[0] = mvali[0]; /* needed for turntable to work */ + mvalball[1]= mvalo[1] = mvali[1]; + dist0= v3d->dist; + + calctrackballvec(&ar->winrct, mvalo, firstvec); + + /* cumultime(0); */ + + if(!G.obedit && (G.f & G_SCULPTMODE) && ob && v3d->pivot_last) { + use_sel= 1; + VecCopyf(ofs, v3d->ofs); + +// XXX VecCopyf(obofs, sculpt_data()->pivot); + Mat4MulVecfl(ob->obmat, obofs); + obofs[0]= -obofs[0]; + obofs[1]= -obofs[1]; + obofs[2]= -obofs[2]; + } + else if (U.uiflag & USER_ORBIT_SELECTION) { + use_sel = 1; + + VECCOPY(ofs, v3d->ofs); + + /* If there's no selection, lastofs is unmodified and last value since static */ +// XXX calculateTransformCenter(V3D_CENTROID, lastofs); + + VECCOPY(obofs, lastofs); + VecMulf(obofs, -1.0f); + } + else if (U.uiflag & USER_ORBIT_ZBUF) { + if ((use_sel= view_autodist(C, scene, ar, v3d, mval, obofs))) { + if (v3d->persp==V3D_PERSP) { + float my_origin[3]; /* original v3d->ofs */ + float my_pivot[3]; /* view */ + + VECCOPY(my_origin, v3d->ofs); + VecMulf(my_origin, -1.0f); /* ofs is flipped */ + + /* Set the dist value to be the distance from this 3d point */ + /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */ + + /* remove dist value */ + upvec[0] = upvec[1] = 0; + upvec[2] = v3d->dist; + Mat3CpyMat4(mat, v3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecSubf(my_pivot, v3d->ofs, upvec); + VecMulf(my_pivot, -1.0f); /* ofs is flipped */ + + /* find a new ofs value that is allong the view axis (rather then the mouse location) */ + lambda_cp_line_ex(obofs, my_pivot, my_origin, dvec); + dist0 = v3d->dist = VecLenf(my_pivot, dvec); + + VecMulf(dvec, -1.0f); + VECCOPY(v3d->ofs, dvec); + } + VecMulf(obofs, -1.0f); + VECCOPY(ofs, v3d->ofs); + } else { + ofs[0] = ofs[1] = ofs[2] = 0.0f; + } + } + else + ofs[0] = ofs[1] = ofs[2] = 0.0f; + + initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]); + + reverse= 1.0f; + if (v3d->persmat[2][1] < 0.0f) + reverse= -1.0f; + + while(TRUE) { +// XXX getmouseco_sc(mval); + + if( (mode==2 && U.viewzoom==USER_ZOOM_CONT) || /* continues zoom always update */ + mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) { /* mouse moved, so update */ + + if(firsttime) { + + firsttime= 0; + /* are we translating, rotating or zooming? */ + if(mode==0) { +// XXX if(v3d->view!=0) scrarea_queue_headredraw(ar); /*for button */ + } + if(v3d->persp==V3D_CAMOB && mode!=1 && v3d->camera) { + v3d->persp= V3D_PERSP; +// XXX scrarea_do_windraw(ar); +// XXX scrarea_queue_headredraw(ar); + } + } + + if(mode==0) { /* view rotate */ + v3d->view= 0; /* need to reset everytime because of view snapping */ + + if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_PERSP; + + if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0]; + mvalball[1]= mval[1]; + + calctrackballvec(&ar->winrct, mvalball, newvec); + + VecSubf(dvec, newvec, firstvec); + + si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]); + si/= (2.0*TRACKBALLSIZE); + + if (U.flag & USER_TRACKBALL) { + Crossf(q1+1, firstvec, newvec); + + Normalize(q1+1); + + /* Allow for rotation beyond the interval + * [-pi, pi] */ + while (si > 1.0) + si -= 2.0; + + /* This relation is used instead of + * phi = asin(si) so that the angle + * of rotation is linearly proportional + * to the distance that the mouse is + * dragged. */ + phi = si * M_PI / 2.0; + + si= sin(phi); + q1[0]= cos(phi); + q1[1]*= si; + q1[2]*= si; + q1[3]*= si; + QuatMul(v3d->viewquat, q1, oldquat); + + if (use_sel) { + /* compute the post multiplication quat, to rotate the offset correctly */ + QUATCOPY(q1, oldquat); + QuatConj(q1); + QuatMul(q1, q1, v3d->viewquat); + + QuatConj(q1); /* conj == inv for unit quat */ + VECCOPY(v3d->ofs, ofs); + VecSubf(v3d->ofs, v3d->ofs, obofs); + QuatMulVecf(q1, v3d->ofs); + VecAddf(v3d->ofs, v3d->ofs, obofs); + } + } else { + /* New turntable view code by John Aughey */ + + float m[3][3]; + float m_inv[3][3]; + float xvec[3] = {1,0,0}; + /* Sensitivity will control how fast the viewport rotates. 0.0035 was + obtained experimentally by looking at viewport rotation sensitivities + on other modeling programs. */ + /* Perhaps this should be a configurable user parameter. */ + const float sensitivity = 0.0035; + + /* Get the 3x3 matrix and its inverse from the quaternion */ + QuatToMat3(v3d->viewquat, m); + Mat3Inv(m_inv,m); + + /* Determine the direction of the x vector (for rotating up and down) */ + /* This can likely be compuated directly from the quaternion. */ + Mat3MulVecfl(m_inv,xvec); + + /* Perform the up/down rotation */ + phi = sensitivity * -(mval[1] - mvalo[1]); + si = sin(phi); + q1[0] = cos(phi); + q1[1] = si * xvec[0]; + q1[2] = si * xvec[1]; + q1[3] = si * xvec[2]; + QuatMul(v3d->viewquat, v3d->viewquat, q1); + + if (use_sel) { + QuatConj(q1); /* conj == inv for unit quat */ + VecSubf(v3d->ofs, v3d->ofs, obofs); + QuatMulVecf(q1, v3d->ofs); + VecAddf(v3d->ofs, v3d->ofs, obofs); + } + + /* Perform the orbital rotation */ + phi = sensitivity * reverse * (mval[0] - mvalo[0]); + q1[0] = cos(phi); + q1[1] = q1[2] = 0.0; + q1[3] = sin(phi); + QuatMul(v3d->viewquat, v3d->viewquat, q1); + + if (use_sel) { + QuatConj(q1); + VecSubf(v3d->ofs, v3d->ofs, obofs); + QuatMulVecf(q1, v3d->ofs); + VecAddf(v3d->ofs, v3d->ofs, obofs); + } + } + + /* check for view snap */ + if (G.qual==LR_CTRLKEY){ + int i; + float viewmat[3][3]; + + static const float thres = 0.93f; //cos(20 deg); + + static float snapquats[39][6] = { + /*{q0, q1, q3, q4, view, oposite_direction}*/ + {COS45, -SIN45, 0.0, 0.0, 1, 0}, //front + {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back + {1.0, 0.0, 0.0, 0.0, 7, 0}, //top + {0.0, -1.0, 0.0, 0.0, 7, 1}, //bottom + {0.5, -0.5, -0.5, -0.5, 3, 0}, //left + {0.5, -0.5, 0.5, 0.5, 3, 1}, //right + + /* some more 45 deg snaps */ + {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0}, + {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0}, + {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0}, + {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0}, + {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0}, + {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0}, + {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0}, + {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0}, + {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0}, + {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0}, + {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0}, + {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0}, + {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0}, + {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0}, + {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0}, + {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0}, + {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0}, + {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0}, + {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0}, + {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0}, + {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0}, + {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0}, + {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0}, + {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0}, + {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0}, + {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0}, + {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0}, + {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0}, + {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0}, + {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0}, + {-COS45, 0.0, 0.0, SIN45, 0, 0}, + {COS45, 0.0, 0.0, SIN45, 0, 0}, + {0.0, 0.0, 0.0, 1.0, 0, 0} + }; + + QuatToMat3(v3d->viewquat, viewmat); + + for (i = 0 ; i < 39; i++){ + float snapmat[3][3]; + float view = (int)snapquats[i][4]; + float oposite_dir = (int)snapquats[i][5]; + + QuatToMat3(snapquats[i], snapmat); + + if ((Inpf(snapmat[0], viewmat[0]) > thres) && + (Inpf(snapmat[1], viewmat[1]) > thres) && + (Inpf(snapmat[2], viewmat[2]) > thres)){ + + QUATCOPY(v3d->viewquat, snapquats[i]); + + v3d->view = view; + if (view){ + if (oposite_dir){ + v3d->flag2 |= V3D_OPP_DIRECTION_NAME; + }else{ + v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME; + } + } + + break; + } + } + } + } + else if(mode==1) { /* translate */ + if(v3d->persp==V3D_CAMOB) { + float max= (float)MAX2(ar->winx, ar->winy); + + v3d->camdx += (mvalo[0]-mval[0])/(max); + v3d->camdy += (mvalo[1]-mval[1])/(max); + CLAMP(v3d->camdx, -1.0f, 1.0f); + CLAMP(v3d->camdy, -1.0f, 1.0f); + preview3d_event= 0; + } + else { + window_to_3d(ar, v3d, dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]); + VecAddf(v3d->ofs, v3d->ofs, dvec); + } + } + else if(mode==2) { + float zfac=1.0; + + /* use initial value (do not use mvalo (that is used to detect mouse moviments)) */ + mvalo[0] = mvali[0]; + mvalo[1] = mvali[1]; + + if(U.viewzoom==USER_ZOOM_CONT) { + // oldstyle zoom + zfac = 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0; + } + else if(U.viewzoom==USER_ZOOM_SCALE) { + int ctr[2], len1, len2; + // method which zooms based on how far you move the mouse + + ctr[0] = (ar->winrct.xmax + ar->winrct.xmin)/2; + ctr[1] = (ar->winrct.ymax + ar->winrct.ymin)/2; + + len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5; + len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5; + + zfac = dist0 * ((float)len2/len1) / v3d->dist; + } + else { /* USER_ZOOM_DOLLY */ + float len1 = (ar->winrct.ymax - mval[1]) + 5; + float len2 = (ar->winrct.ymax - mvalo[1]) + 5; + zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / v3d->dist; + } + + if(zfac != 1.0 && zfac*v3d->dist > 0.001*v3d->grid && + zfac*v3d->dist < 10.0*v3d->far) + view_zoom_mouseloc(ar, v3d, zfac, mval_area); + + + if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (v3d->persp==V3D_PERSP)) { + /* Secret apricot feature, translate the view when in continues mode */ + upvec[0] = upvec[1] = 0; + upvec[2] = (dist0 - v3d->dist) * v3d->grid; + v3d->dist = dist0; + Mat3CpyMat4(mat, v3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecAddf(v3d->ofs, v3d->ofs, upvec); + } else { + /* these limits are in toets.c too */ + if(v3d->dist<0.001*v3d->grid) v3d->dist= 0.001*v3d->grid; + if(v3d->dist>10.0*v3d->far) v3d->dist=10.0*v3d->far; + } + + if(v3d->persp==V3D_ORTHO || v3d->persp==V3D_CAMOB) preview3d_event= 0; + } + + + + mvalo[0]= mval[0]; + mvalo[1]= mval[1]; + +// XXX if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0); + + /* If in retopo paint mode, update lines */ + if(retopo_mesh_paint_check() && v3d->retopo_view_data) { + v3d->retopo_view_data->queue_matrix_update= 1; + retopo_paint_view_update(v3d); + } + +// XXX scrarea_do_windraw(ar); +// XXX screen_swapbuffers(); + } + else { +// short val; +// unsigned short event; + /* we need to empty the queue... when you do this very long it overflows */ +// XX while(qtest()) event= extern_qread(&val); + +// XXX BIF_wait_for_statechange(); + } + + /* this in the end, otherwise get_mbut does not work on a PC... */ +// XXX if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break; + } + + if(v3d->depths) v3d->depths->damaged= 1; +// XXX retopo_queue_updates(v3d); +// XXX allqueue(REDRAWVIEW3D, 0); + +// XXX if(preview3d_event) +// BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT); +// else +// BIF_view3d_previewrender_signal(ar, PR_PROJECTED); + +} + + +void viewmoveNDOF(Scene *scene, View3D *v3d, int mode) +{ + float fval[7]; + float dvec[3]; + float sbadjust = 1.0f; + float len; + short use_sel = 0; + Object *ob = OBACT; + float m[3][3]; + float m_inv[3][3]; + float xvec[3] = {1,0,0}; + float yvec[3] = {0,-1,0}; + float zvec[3] = {0,0,1}; + float phi, si; + float q1[4]; + float obofs[3]; + float reverse; + //float diff[4]; + float d, curareaX, curareaY; + float mat[3][3]; + float upvec[3]; + + /* Sensitivity will control how fast the view rotates. The value was + * obtained experimentally by tweaking until the author didn't get dizzy watching. + * Perhaps this should be a configurable user parameter. + */ + float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */ + float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */ + float zsens = 0.3f; /* zoom sensitivity */ + + const float minZoom = -30.0f; + const float maxZoom = 300.0f; + + //reset view type + v3d->view = 0; +//printf("passing here \n"); +// + if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) { + use_sel = 1; + } + + if((dz_flag)||v3d->dist==0) { + dz_flag = 0; + v3d->dist = m_dist; + upvec[0] = upvec[1] = 0; + upvec[2] = v3d->dist; + Mat3CpyMat4(mat, v3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecAddf(v3d->ofs, v3d->ofs, upvec); + } + + /*---------------------------------------------------- + * sometimes this routine is called from headerbuttons + * viewmove needs to refresh the screen + */ +// XXX areawinset(curarea->win); + + /*---------------------------------------------------- + * record how much time has passed. clamp at 10 Hz + * pretend the previous frame occured at the clamped time + */ +// now = PIL_check_seconds_timer(); + // frametime = (now - prevTime); + // if (frametime > 0.1f){ /* if more than 1/10s */ + // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */ +// } +// prevTime = now; + // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */ + + /* fetch the current state of the ndof device & enforce dominant mode if selected */ +// XXX getndof(fval); + if (v3d->ndoffilter) + filterNDOFvalues(fval); + + + // put scaling back here, was previously in ghostwinlay + fval[0] = fval[0] * (1.0f/600.0f); + fval[1] = fval[1] * (1.0f/600.0f); + fval[2] = fval[2] * (1.0f/1100.0f); + fval[3] = fval[3] * 0.00005f; + fval[4] =-fval[4] * 0.00005f; + fval[5] = fval[5] * 0.00005f; + fval[6] = fval[6] / 1000000.0f; + + // scale more if not in perspective mode + if (v3d->persp == V3D_ORTHO) { + fval[0] = fval[0] * 0.05f; + fval[1] = fval[1] * 0.05f; + fval[2] = fval[2] * 0.05f; + fval[3] = fval[3] * 0.9f; + fval[4] = fval[4] * 0.9f; + fval[5] = fval[5] * 0.9f; + zsens *= 8; + } + + + /* set object offset */ + if (ob) { + obofs[0] = -ob->obmat[3][0]; + obofs[1] = -ob->obmat[3][1]; + obofs[2] = -ob->obmat[3][2]; + } + else { + VECCOPY(obofs, v3d->ofs); + } + + /* calc an adjustment based on distance from camera + disabled per patch 14402 */ + d = 1.0f; + +/* if (ob) { + VecSubf(diff, obofs, v3d->ofs); + d = VecLength(diff); + } +*/ + + reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f; + + /*---------------------------------------------------- + * ndof device pan + */ + psens *= 1.0f + d; + curareaX = sbadjust * psens * fval[0]; + curareaY = sbadjust * psens * fval[1]; + dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0]; + dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1]; + dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2]; + VecAddf(v3d->ofs, v3d->ofs, dvec); + + /*---------------------------------------------------- + * ndof device dolly + */ + len = zsens * sbadjust * fval[2]; + + if (v3d->persp==V3D_CAMOB) { + if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */ + v3d->camzoom+= 10.0f * -len; + } + if (v3d->camzoom < minZoom) v3d->camzoom = minZoom; + else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom; + } + else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) { + v3d->dist*=(1.0 + len); + } + + + /*---------------------------------------------------- + * ndof device turntable + * derived from the turntable code in viewmove + */ + + /* Get the 3x3 matrix and its inverse from the quaternion */ + QuatToMat3(v3d->viewquat, m); + Mat3Inv(m_inv,m); + + /* Determine the direction of the x vector (for rotating up and down) */ + /* This can likely be compuated directly from the quaternion. */ + Mat3MulVecfl(m_inv,xvec); + Mat3MulVecfl(m_inv,yvec); + Mat3MulVecfl(m_inv,zvec); + + /* Perform the up/down rotation */ + phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */ + si = sin(phi); + q1[0] = cos(phi); + q1[1] = si * xvec[0]; + q1[2] = si * xvec[1]; + q1[3] = si * xvec[2]; + QuatMul(v3d->viewquat, v3d->viewquat, q1); + + if (use_sel) { + QuatConj(q1); /* conj == inv for unit quat */ + VecSubf(v3d->ofs, v3d->ofs, obofs); + QuatMulVecf(q1, v3d->ofs); + VecAddf(v3d->ofs, v3d->ofs, obofs); + } + + /* Perform the orbital rotation */ + /* Perform the orbital rotation + If the seen Up axis is parallel to the zoom axis, rotation should be + achieved with a pure Roll motion (no Spin) on the device. When you start + to tilt, moving from Top to Side view, Spinning will increasingly become + more relevant while the Roll component will decrease. When a full + Side view is reached, rotations around the world's Up axis are achieved + with a pure Spin-only motion. In other words the control of the spinning + around the world's Up axis should move from the device's Spin axis to the + device's Roll axis depending on the orientation of the world's Up axis + relative to the screen. */ + //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */ + phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]); + q1[0] = cos(phi); + q1[1] = q1[2] = 0.0; + q1[3] = sin(phi); + QuatMul(v3d->viewquat, v3d->viewquat, q1); + + if (use_sel) { + QuatConj(q1); + VecSubf(v3d->ofs, v3d->ofs, obofs); + QuatMulVecf(q1, v3d->ofs); + VecAddf(v3d->ofs, v3d->ofs, obofs); + } + + /*---------------------------------------------------- + * refresh the screen + */ +// XXX scrarea_do_windraw(curarea); +} + + + + diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index aa950b87238..0f4ecd2ef7b 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -29,6 +29,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_object_types.h" #include "DNA_space_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index d0e49373562..331b5553869 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -30,6 +30,11 @@ /* internal exports only */ +struct wmWindow; +struct BoundBox; +struct Object; +struct DerivedMesh; + typedef struct ViewDepths { unsigned short w, h; float *depths; @@ -43,34 +48,75 @@ typedef struct ViewDepths { #define DRAW_CONSTCOLOR 2 #define DRAW_SCENESET 4 +#define V3D_XRAY 1 +#define V3D_TRANSP 2 + /* project short */ #define IS_CLIPPED 12000 /* view3d_header.c */ void view3d_header_buttons(const bContext *C, ARegion *ar); +/* drawobject.c */ +void draw_object(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag); +int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt); + +/* drawmesh.c */ +void draw_mesh_textured(Scene *scene, View3D *v3d, Object *ob, struct DerivedMesh *dm, int faceselect); + /* view3d_draw.c */ void drawview3dspace(const bContext *C, ARegion *ar, View3D *v3d); +void draw_depth(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, int (* func)(void *)); int view3d_test_clipping(View3D *v3d, float *vec); +void view3d_clr_clipping(void); +void view3d_set_clipping(View3D *v3d); +void add_view3d_after(View3D *v3d, Base *base, int type, int flag); +void make_axis_color(char *col, char *col2, char axis); + void circf(float x, float y, float rad); void circ(float x, float y, float rad); void view3d_update_depths(ARegion *ar, View3D *v3d); /* view3d_view.c */ float *give_cursor(Scene *scene, View3D *v3d); +void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3]); +void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3]); + void initgrabz(View3D *v3d, float x, float y, float z); void window_to_3d(ARegion *ar, View3D *v3d, float *vec, short mx, short my); +int boundbox_clip(View3D *v3d, float obmat[][4], struct BoundBox *bb); + +void view3d_project_short_clip(ARegion *ar, View3D *v3d, float *vec, short *adr, float projmat[4][4], float wmat[4][4]); +void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4]); void view3d_project_float(ARegion *a, float *vec, float *adr, float mat[4][4]); +void view3d_get_object_project_mat(View3D *v3d, struct Object *ob, float pmat[4][4], float vmat[4][4]); +void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]); + void project_short(ARegion *ar, View3D *v3d, float *vec, short *adr); void project_int(ARegion *ar, View3D *v3d, float *vec, int *adr); void project_int_noclip(ARegion *ar, View3D *v3d, float *vec, int *adr); void project_short_noclip(ARegion *ar, View3D *v3d, float *vec, short *adr); void project_float(ARegion *ar, View3D *v3d, float *vec, float *adr); void project_float_noclip(ARegion *ar, View3D *v3d, float *vec, float *adr); + int get_view3d_viewplane(View3D *v3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize); +void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens); +void obmat_to_viewmat(View3D *v3d, Object *ob, short smooth); + +short view3d_opengl_select(bContext *C, Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, unsigned int bufsize, rcti *input); +void initlocalview(Scene *scene, ARegion *ar, View3D *v3d); +void restore_localviewdata(View3D *vd); +void endlocalview(Scene *scene, ScrArea *sa); + +void centerview(ARegion *ar, View3D *v3d); +void view3d_home(View3D *v3d, ARegion *ar, int center); + +void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3]); +void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens); +void smooth_view_to_camera(View3D *v3d); -void setwinmatrixview3d(wmWindow *win, View3D *v3d, int winx, int winy, rctf *rect); /* rect: for picking */ +void setwinmatrixview3d(struct wmWindow *win, View3D *v3d, int winx, int winy, rctf *rect); /* rect: for picking */ void setviewmatrixview3d(View3D *v3d); #endif /* ED_VIEW3D_INTERN_H */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 26566ec7b8a..a7d8360157d 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -32,6 +32,7 @@ #include <float.h> #include "DNA_action_types.h" +#include "DNA_armature_types.h" #include "DNA_camera_types.h" #include "DNA_lamp_types.h" #include "DNA_object_types.h" @@ -48,10 +49,12 @@ #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BKE_anim.h" #include "BKE_action.h" #include "BKE_context.h" #include "BKE_object.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" @@ -72,6 +75,7 @@ #include "view3d_intern.h" // own include +#define BL_NEAR_CLIP 0.001 float *give_cursor(Scene *scene, View3D *v3d) { @@ -79,6 +83,49 @@ float *give_cursor(Scene *scene, View3D *v3d) else return scene->cursor; } +/* create intersection coordinates in view Z direction at mouse coordinates */ +void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3]) +{ + float vec[4]; + + if(v3d->persp != V3D_ORTHO){ + vec[0]= 2.0f * mval[0] / ar->winx - 1; + vec[1]= 2.0f * mval[1] / ar->winy - 1; + vec[2]= -1.0f; + vec[3]= 1.0f; + + Mat4MulVec4fl(v3d->persinv, vec); + VecMulf(vec, 1.0f / vec[3]); + + VECCOPY(ray_start, v3d->viewinv[3]); + VECSUB(vec, vec, ray_start); + Normalize(vec); + + VECADDFAC(ray_start, v3d->viewinv[3], vec, v3d->near); + VECADDFAC(ray_end, v3d->viewinv[3], vec, v3d->far); + } + else { + vec[0] = 2.0f * mval[0] / ar->winx - 1; + vec[1] = 2.0f * mval[1] / ar->winy - 1; + vec[2] = 0.0f; + vec[3] = 1.0f; + + Mat4MulVec4fl(v3d->persinv, vec); + + VECADDFAC(ray_start, vec, v3d->viewinv[2], 1000.0f); + VECADDFAC(ray_end, vec, v3d->viewinv[2], -1000.0f); + } +} + +/* create intersection ray in view Z direction at mouse coordinates */ +void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3]) +{ + float ray_end[3]; + + viewline(ar, v3d, mval, ray_start, ray_end); + VecSubf(ray_normal, ray_end, ray_start); + Normalize(ray_normal); +} void initgrabz(View3D *v3d, float x, float y, float z) @@ -110,6 +157,75 @@ void window_to_3d(ARegion *ar, View3D *v3d, float *vec, short mx, short my) vec[2]= (v3d->persinv[0][2]*dx + v3d->persinv[1][2]*dy); } +void view3d_get_object_project_mat(View3D *v3d, Object *ob, float pmat[4][4], float vmat[4][4]) +{ + Mat4MulMat4(vmat, ob->obmat, v3d->viewmat); + Mat4MulMat4(pmat, vmat, v3d->winmat); + Mat4CpyMat4(vmat, ob->obmat); +} + +/* projectmat brings it to window coords, wmat to rotated world space */ +void view3d_project_short_clip(ARegion *ar, View3D *v3d, float *vec, short *adr, float projmat[4][4], float wmat[4][4]) +{ + float fx, fy, vec4[4]; + + adr[0]= IS_CLIPPED; + + /* clipplanes in eye space */ + if(v3d->flag & V3D_CLIPPING) { + VECCOPY(vec4, vec); + Mat4MulVecfl(wmat, vec4); + if(view3d_test_clipping(v3d, vec4)) + return; + } + + VECCOPY(vec4, vec); + vec4[3]= 1.0; + + Mat4MulVec4fl(projmat, vec4); + + /* clipplanes in window space */ + if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ + fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); + + if( fx>0 && fx<ar->winx) { + + fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); + + if(fy>0.0 && fy< (float)ar->winy) { + adr[0]= (short)floor(fx); + adr[1]= (short)floor(fy); + } + } + } +} + +void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4]) +{ + float fx, fy, vec4[4]; + + adr[0]= IS_CLIPPED; + + VECCOPY(vec4, vec); + vec4[3]= 1.0; + + Mat4MulVec4fl(mat, vec4); + + if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ + fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); + + if( fx>-32700 && fx<32700) { + + fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); + + if(fy>-32700.0 && fy<32700.0) { + adr[0]= (short)floor(fx); + adr[1]= (short)floor(fy); + } + } + } +} + void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]) { float vec4[4]; @@ -128,8 +244,40 @@ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]) } } - -#define BL_NEAR_CLIP 0.001 +int boundbox_clip(View3D *v3d, float obmat[][4], BoundBox *bb) +{ + /* return 1: draw */ + + float mat[4][4]; + float vec[4], min, max; + int a, flag= -1, fl; + + if(bb==NULL) return 1; + if(bb->flag & OB_BB_DISABLED) return 1; + + Mat4MulMat4(mat, obmat, v3d->persmat); + + for(a=0; a<8; a++) { + VECCOPY(vec, bb->vec[a]); + vec[3]= 1.0; + Mat4MulVec4fl(mat, vec); + max= vec[3]; + min= -vec[3]; + + fl= 0; + if(vec[0] < min) fl+= 1; + if(vec[0] > max) fl+= 2; + if(vec[1] < min) fl+= 4; + if(vec[1] > max) fl+= 8; + if(vec[2] < min) fl+= 16; + if(vec[2] > max) fl+= 32; + + flag &= fl; + if(flag==0) return 1; + } + + return 0; +} void project_short(ARegion *ar, View3D *v3d, float *vec, short *adr) /* clips */ { @@ -427,125 +575,9 @@ void setwinmatrixview3d(wmWindow *win, View3D *v3d, int winx, int winy, rctf *re } -/* SMOOTHVIEW */ -void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens) -{ - /* View Animation enabled */ - if (U.smooth_viewtx) { - int i; - char changed = 0; - float step = 0.0, step_inv; - float orig_dist; - float orig_lens; - float orig_quat[4]; - float orig_ofs[3]; - - double time_allowed, time_current, time_start; - - /* if there is no difference, return */ - changed = 0; /* zero means no difference */ - if (dist) { - if ((*dist) != v3d->dist) - changed = 1; - } - - if (lens) { - if ((*lens) != v3d->lens) - changed = 1; - } - - if (!changed && ofs) { - if ((ofs[0]!=v3d->ofs[0]) || - (ofs[1]!=v3d->ofs[1]) || - (ofs[2]!=v3d->ofs[2]) ) - changed = 1; - } - - if (!changed && quat ) { - if ((quat[0]!=v3d->viewquat[0]) || - (quat[1]!=v3d->viewquat[1]) || - (quat[2]!=v3d->viewquat[2]) || - (quat[3]!=v3d->viewquat[3]) ) - changed = 1; - } - - /* The new view is different from the old one - * so animate the view */ - if (changed) { - - /* store original values */ - VECCOPY(orig_ofs, v3d->ofs); - QUATCOPY(orig_quat, v3d->viewquat); - orig_dist = v3d->dist; - orig_lens = v3d->lens; - - time_allowed= (float)U.smooth_viewtx / 1000.0; - time_current = time_start = PIL_check_seconds_timer(); - - /* if this is view rotation only - * we can decrease the time allowed by - * the angle between quats - * this means small rotations wont lag */ - if (quat && !ofs && !dist) { - float vec1[3], vec2[3]; - VECCOPY(vec1, quat); - VECCOPY(vec2, v3d->viewquat); - Normalize(vec1); - Normalize(vec2); - /* scale the time allowed by the rotation */ - time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); - } - - while (time_start + time_allowed > time_current) { - - step = (float)((time_current-time_start) / time_allowed); - - /* ease in/out */ - if (step < 0.5) step = (float)pow(step*2, 2)/2; - else step = (float)1-(pow(2*(1-step),2)/2); - - step_inv = 1-step; - - if (ofs) - for (i=0; i<3; i++) - v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv; - - - if (quat) - QuatInterpol(v3d->viewquat, orig_quat, quat, step); - - if (dist) - v3d->dist = ((*dist)*step) + (orig_dist*step_inv); - - if (lens) - v3d->lens = ((*lens)*step) + (orig_lens*step_inv); - - /*redraw the view*/ -// scrarea_do_windraw(ar); -// screen_swapbuffers(); - - time_current= PIL_check_seconds_timer(); - } - } - } - - /* set these values even if animation is enabled because flaot - * error will make then not quite accurate */ - if (ofs) - VECCOPY(v3d->ofs, ofs); - if (quat) - QUATCOPY(v3d->viewquat, quat); - if (dist) - v3d->dist = *dist; - if (lens) - v3d->lens = *lens; - -} - - /* Gets the lens and clipping values from a camera of lamp type object */ -void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend) +static void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend) { if (!ob) return; @@ -712,3 +744,674 @@ void setcameratoview3d(View3D *v3d) /*}*/ v3d->viewquat[0]= -v3d->viewquat[0]; } + + +/* IGLuint-> GLuint*/ +/* Warning: be sure to account for a negative return value +* This is an error, "Too many objects in select buffer" +* and no action should be taken (can crash blender) if this happens +*/ +short view3d_opengl_select(bContext *C, Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, unsigned int bufsize, rcti *input) +{ + rctf rect; + short code, hits; + + G.f |= G_PICKSEL; + + /* case not a border select */ + if(input->xmin==input->xmax) { + rect.xmin= input->xmin-12; // seems to be default value for bones only now + rect.xmax= input->xmin+12; + rect.ymin= input->ymin-12; + rect.ymax= input->xmin+12; + } + else { + rect.xmin= input->xmin; + rect.xmax= input->xmax; + rect.ymin= input->ymin; + rect.ymax= input->ymax; + } + + /* get rid of overlay button matrix XXX ?*/ + setwinmatrixview3d(CTX_wm_window(C), v3d, ar->winx, ar->winy, &rect); + Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat); + + if(v3d->drawtype > OB_WIRE) { + v3d->zbuf= TRUE; + glEnable(GL_DEPTH_TEST); + } + + if(v3d->flag & V3D_CLIPPING) + view3d_set_clipping(v3d); + + glSelectBuffer( bufsize, (GLuint *)buffer); + glRenderMode(GL_SELECT); + glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ + glPushName(-1); + code= 1; + + if(G.obedit && G.obedit->type==OB_MBALL) { + draw_object(C, scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR); + } + else if ((G.obedit && G.obedit->type==OB_ARMATURE)) { + draw_object(C, scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR); + } + else { + Base *base; + + v3d->xray= TRUE; // otherwise it postpones drawing + for(base= scene->base.first; base; base= base->next) { + if(base->lay & v3d->lay) { + + if (base->object->restrictflag & OB_RESTRICT_SELECT) + base->selcol= 0; + else { + base->selcol= code; + glLoadName(code); + draw_object(C, scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR); + + /* we draw group-duplicators for selection too */ + if((base->object->transflag & OB_DUPLI) && base->object->dup_group) { + ListBase *lb; + DupliObject *dob; + Base tbase; + + tbase.flag= OB_FROMDUPLI; + lb= object_duplilist(scene, base->object); + + for(dob= lb->first; dob; dob= dob->next) { + tbase.object= dob->ob; + Mat4CpyMat4(dob->ob->obmat, dob->mat); + + draw_object(C, scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR); + + Mat4CpyMat4(dob->ob->obmat, dob->omat); + } + free_object_duplilist(lb); + } + code++; + } + } + } + v3d->xray= FALSE; // restore + } + + glPopName(); /* see above (pushname) */ + hits= glRenderMode(GL_RENDER); + + G.f &= ~G_PICKSEL; + setwinmatrixview3d(CTX_wm_window(C), v3d, ar->winx, ar->winy, NULL); + Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat); + + if(v3d->drawtype > OB_WIRE) { + v3d->zbuf= 0; + glDisable(GL_DEPTH_TEST); + } +// XXX persp(PERSP_WIN); + + if(v3d->flag & V3D_CLIPPING) + view3d_clr_clipping(); + + if(hits<0) printf("Too many objects in select buffer\n"); // XXX make error message + + return hits; +} + +// XXX solve: localview on region level? no.... layers are area, so all regions in area have to be set +static unsigned int free_localbit(void) +{ + unsigned int lay; + ScrArea *sa; + bScreen *sc; + + lay= 0; + + /* sometimes we loose a localview: when an area is closed */ + /* check all areas: which localviews are in use? */ + for(sc= G.main->screen.first; sc; sc= sc->id.next) { + for(sa= sc->areabase.first; sa; sa= sa->next) { + SpaceLink *sl= sa->spacedata.first; + for(; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + lay |= v3d->lay; + } + } + } + } + + if( (lay & 0x01000000)==0) return 0x01000000; + if( (lay & 0x02000000)==0) return 0x02000000; + if( (lay & 0x04000000)==0) return 0x04000000; + if( (lay & 0x08000000)==0) return 0x08000000; + if( (lay & 0x10000000)==0) return 0x10000000; + if( (lay & 0x20000000)==0) return 0x20000000; + if( (lay & 0x40000000)==0) return 0x40000000; + if( (lay & 0x80000000)==0) return 0x80000000; + + return 0; +} + + +void initlocalview(Scene *scene, ARegion *ar, View3D *v3d) +{ + Base *base; + float size = 0.0, min[3], max[3], afm[3]; + unsigned int locallay; + int ok=0; + + if(v3d->localvd) return; + + INIT_MINMAX(min, max); + + locallay= free_localbit(); + + if(locallay==0) { + printf("Sorry, no more than 8 localviews\n"); // XXX error + ok= 0; + } + else { + if(G.obedit) { + minmax_object(G.obedit, min, max); + + ok= 1; + + BASACT->lay |= locallay; + G.obedit->lay= BASACT->lay; + } + else { + base= FIRSTBASE; + while(base) { + if TESTBASE(base) { + minmax_object(base->object, min, max); + base->lay |= locallay; + base->object->lay= base->lay; + ok= 1; + } + base= base->next; + } + } + + afm[0]= (max[0]-min[0]); + afm[1]= (max[1]-min[1]); + afm[2]= (max[2]-min[2]); + size= 0.7*MAX3(afm[0], afm[1], afm[2]); + if(size<=0.01) size= 0.01; + } + + if(ok) { + v3d->localvd= MEM_mallocN(sizeof(View3D), "localview"); + memcpy(v3d->localvd, v3d, sizeof(View3D)); + + v3d->ofs[0]= -(min[0]+max[0])/2.0; + v3d->ofs[1]= -(min[1]+max[1])/2.0; + v3d->ofs[2]= -(min[2]+max[2])/2.0; + + v3d->dist= size; + + // correction for window aspect ratio + if(ar->winy>2 && ar->winx>2) { + size= (float)ar->winx/(float)ar->winy; + if(size<1.0) size= 1.0/size; + v3d->dist*= size; + } + + if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; + if (v3d->near> 0.1) v3d->near= 0.1; + + v3d->cursor[0]= -v3d->ofs[0]; + v3d->cursor[1]= -v3d->ofs[1]; + v3d->cursor[2]= -v3d->ofs[2]; + + v3d->lay= locallay; + +// XXX countall(); +// XXX scrarea_queue_winredraw(curarea); + } + else { + /* clear flags */ + base= FIRSTBASE; + while(base) { + if( base->lay & locallay ) { + base->lay-= locallay; + if(base->lay==0) base->lay= v3d->layact; + if(base->object != G.obedit) base->flag |= SELECT; + base->object->lay= base->lay; + } + base= base->next; + } +// XXX scrarea_queue_headredraw(curarea); + + v3d->localview= 0; + } +// XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); +} + +void centerview(ARegion *ar, View3D *v3d) /* like a localview without local! */ +{ + Object *ob= OBACT; + float size, min[3], max[3], afm[3]; + int ok=0; + + /* SMOOTHVIEW */ + float new_ofs[3]; + float new_dist; + + INIT_MINMAX(min, max); + + if (G.f & G_WEIGHTPAINT) { + /* hardcoded exception, we look for the one selected armature */ + /* this is weak code this way, we should make a generic active/selection callback interface once... */ + Base *base; + for(base=FIRSTBASE; base; base= base->next) { + if(TESTBASELIB(base)) { + if(base->object->type==OB_ARMATURE) + if(base->object->flag & OB_POSEMODE) + break; + } + } + if(base) + ob= base->object; + } + + + if(G.obedit) { +// XXX ok = minmax_verts(min, max); /* only selected */ + } + else if(ob && (ob->flag & OB_POSEMODE)) { + if(ob->pose) { + bArmature *arm= ob->data; + bPoseChannel *pchan; + float vec[3]; + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(pchan->bone->flag & BONE_SELECTED) { + if(pchan->bone->layer & arm->layer) { + ok= 1; + VECCOPY(vec, pchan->pose_head); + Mat4MulVecfl(ob->obmat, vec); + DO_MINMAX(vec, min, max); + VECCOPY(vec, pchan->pose_tail); + Mat4MulVecfl(ob->obmat, vec); + DO_MINMAX(vec, min, max); + } + } + } + } + } + else if (FACESEL_PAINT_TEST) { +// XXX ok= minmax_tface(min, max); + } + else if (G.f & G_PARTICLEEDIT) { +// XXX ok= PE_minmax(min, max); + } + else { + Base *base= FIRSTBASE; + while(base) { + if TESTBASE(base) { + minmax_object(base->object, min, max); + /* account for duplis */ + minmax_object_duplis(base->object, min, max); + + ok= 1; + } + base= base->next; + } + } + + if(ok==0) return; + + afm[0]= (max[0]-min[0]); + afm[1]= (max[1]-min[1]); + afm[2]= (max[2]-min[2]); + size= 0.7f*MAX3(afm[0], afm[1], afm[2]); + + if(size <= v3d->near*1.5f) size= v3d->near*1.5f; + + new_ofs[0]= -(min[0]+max[0])/2.0f; + new_ofs[1]= -(min[1]+max[1])/2.0f; + new_ofs[2]= -(min[2]+max[2])/2.0f; + + new_dist = size; + + /* correction for window aspect ratio */ + if(ar->winy>2 && ar->winx>2) { + size= (float)ar->winx/(float)ar->winy; + if(size<1.0f) size= 1.0f/size; + new_dist*= size; + } + + v3d->cursor[0]= -new_ofs[0]; + v3d->cursor[1]= -new_ofs[1]; + v3d->cursor[2]= -new_ofs[2]; + + if (v3d->persp==V3D_CAMOB && v3d->camera) { + float orig_lens= v3d->lens; + + v3d->persp=V3D_PERSP; + v3d->dist= 0.0f; + view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens); + smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens); + } else { + if(v3d->persp==V3D_CAMOB) + v3d->persp= V3D_PERSP; + + smooth_view(v3d, new_ofs, NULL, &new_dist, NULL); + } +// XXX scrarea_queue_winredraw(curarea); +// XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); + +} + + +void restore_localviewdata(View3D *vd) +{ + if(vd->localvd==0) return; + + VECCOPY(vd->ofs, vd->localvd->ofs); + vd->dist= vd->localvd->dist; + vd->persp= vd->localvd->persp; + vd->view= vd->localvd->view; + vd->near= vd->localvd->near; + vd->far= vd->localvd->far; + vd->lay= vd->localvd->lay; + vd->layact= vd->localvd->layact; + vd->drawtype= vd->localvd->drawtype; + vd->camera= vd->localvd->camera; + QUATCOPY(vd->viewquat, vd->localvd->viewquat); + +} + +void endlocalview(Scene *scene, ScrArea *sa) +{ + View3D *v3d; + struct Base *base; + unsigned int locallay; + + if(sa->spacetype!=SPACE_VIEW3D) return; + v3d= sa->spacedata.first; + + if(v3d->localvd) { + + locallay= v3d->lay & 0xFF000000; + + restore_localviewdata(v3d); + + MEM_freeN(v3d->localvd); + v3d->localvd= 0; + v3d->localview= 0; + + /* for when in other window the layers have changed */ + if(v3d->scenelock) v3d->lay= scene->lay; + + base= FIRSTBASE; + while(base) { + if( base->lay & locallay ) { + base->lay-= locallay; + if(base->lay==0) base->lay= v3d->layact; + if(base->object != G.obedit) { + base->flag |= SELECT; + base->object->flag |= SELECT; + } + base->object->lay= base->lay; + } + base= base->next; + } + +// XXX countall(); +// XXX allqueue(REDRAWVIEW3D, 0); /* because of select */ +// XXX allqueue(REDRAWOOPS, 0); /* because of select */ +// XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); + } +} + +void view3d_home(View3D *v3d, ARegion *ar, int center) +{ + Base *base; + float size, min[3], max[3], afm[3]; + int ok= 1, onedone=0; + + if(center) { + min[0]= min[1]= min[2]= 0.0f; + max[0]= max[1]= max[2]= 0.0f; + } + else { + INIT_MINMAX(min, max); + } + + for(base= FIRSTBASE; base; base= base->next) { + if(base->lay & v3d->lay) { + onedone= 1; + minmax_object(base->object, min, max); + } + } + if(!onedone) return; + + afm[0]= (max[0]-min[0]); + afm[1]= (max[1]-min[1]); + afm[2]= (max[2]-min[2]); + size= 0.7f*MAX3(afm[0], afm[1], afm[2]); + if(size==0.0) ok= 0; + + if(ok) { + float new_dist; + float new_ofs[3]; + + new_dist = size; + new_ofs[0]= -(min[0]+max[0])/2.0f; + new_ofs[1]= -(min[1]+max[1])/2.0f; + new_ofs[2]= -(min[2]+max[2])/2.0f; + + // correction for window aspect ratio + if(ar->winy>2 && ar->winx>2) { + size= (float)ar->winx/(float)ar->winy; + if(size<1.0) size= 1.0f/size; + new_dist*= size; + } + + if (v3d->persp==V3D_CAMOB && v3d->camera) { + /* switch out of camera view */ + float orig_lens= v3d->lens; + + v3d->persp= V3D_PERSP; + v3d->dist= 0.0; + view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens); + smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens); + + } else { + if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; + smooth_view(v3d, new_ofs, NULL, &new_dist, NULL); + } +// XXX scrarea_queue_winredraw(curarea); + } +// XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); + +} + +void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3]) +{ + float alignaxis[3] = {0.0, 0.0, 0.0}; + float norm[3], axis[3], angle, new_quat[4]; + + if(axisidx > 0) alignaxis[axisidx-1]= 1.0; + else alignaxis[-axisidx-1]= -1.0; + + VECCOPY(norm, vec); + Normalize(norm); + + angle= (float)acos(Inpf(alignaxis, norm)); + Crossf(axis, alignaxis, norm); + VecRotToQuat(axis, -angle, new_quat); + + v3d->view= 0; + + if (v3d->persp==V3D_CAMOB && v3d->camera) { + /* switch out of camera view */ + float orig_ofs[3]; + float orig_dist= v3d->dist; + float orig_lens= v3d->lens; + + VECCOPY(orig_ofs, v3d->ofs); + v3d->persp= V3D_PERSP; + v3d->dist= 0.0; + view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens); + smooth_view(v3d, orig_ofs, new_quat, &orig_dist, &orig_lens); + } else { + if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */ + smooth_view(v3d, NULL, new_quat, NULL, NULL); + } +} + + + +/* SMOOTHVIEW */ +void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens) +{ + /* View Animation enabled */ + if (U.smooth_viewtx) { + int i; + char changed = 0; + float step = 0.0, step_inv; + float orig_dist; + float orig_lens; + float orig_quat[4]; + float orig_ofs[3]; + + double time_allowed, time_current, time_start; + + /* if there is no difference, return */ + changed = 0; /* zero means no difference */ + if (dist) { + if ((*dist) != v3d->dist) + changed = 1; + } + + if (lens) { + if ((*lens) != v3d->lens) + changed = 1; + } + + if (!changed && ofs) { + if ((ofs[0]!=v3d->ofs[0]) || + (ofs[1]!=v3d->ofs[1]) || + (ofs[2]!=v3d->ofs[2]) ) + changed = 1; + } + + if (!changed && quat ) { + if ((quat[0]!=v3d->viewquat[0]) || + (quat[1]!=v3d->viewquat[1]) || + (quat[2]!=v3d->viewquat[2]) || + (quat[3]!=v3d->viewquat[3]) ) + changed = 1; + } + + /* The new view is different from the old one + * so animate the view */ + if (changed) { + + /* store original values */ + VECCOPY(orig_ofs, v3d->ofs); + QUATCOPY(orig_quat, v3d->viewquat); + orig_dist = v3d->dist; + orig_lens = v3d->lens; + + time_allowed= (float)U.smooth_viewtx / 1000.0; + time_current = time_start = PIL_check_seconds_timer(); + + /* if this is view rotation only + * we can decrease the time allowed by + * the angle between quats + * this means small rotations wont lag */ + if (quat && !ofs && !dist) { + float vec1[3], vec2[3]; + VECCOPY(vec1, quat); + VECCOPY(vec2, v3d->viewquat); + Normalize(vec1); + Normalize(vec2); + /* scale the time allowed by the rotation */ + time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); + } + + while (time_start + time_allowed > time_current) { + + step = (float)((time_current-time_start) / time_allowed); + + /* ease in/out */ + if (step < 0.5) step = (float)pow(step*2, 2)/2; + else step = (float)1-(pow(2*(1-step),2)/2); + + step_inv = 1-step; + + if (ofs) + for (i=0; i<3; i++) + v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv; + + + if (quat) + QuatInterpol(v3d->viewquat, orig_quat, quat, step); + + if (dist) + v3d->dist = ((*dist)*step) + (orig_dist*step_inv); + + if (lens) + v3d->lens = ((*lens)*step) + (orig_lens*step_inv); + + /*redraw the view*/ + // scrarea_do_windraw(ar); + // screen_swapbuffers(); + + time_current= PIL_check_seconds_timer(); + } + } + } + + /* set these values even if animation is enabled because flaot + * error will make then not quite accurate */ + if (ofs) + VECCOPY(v3d->ofs, ofs); + if (quat) + QUATCOPY(v3d->viewquat, quat); + if (dist) + v3d->dist = *dist; + if (lens) + v3d->lens = *lens; + +} + +/* For use with smooth view +* +* the current view is unchanged, blend between the current view and the +* camera view +* */ +void smooth_view_to_camera(View3D *v3d) +{ + if (!U.smooth_viewtx || !v3d->camera || v3d->persp != V3D_CAMOB) { + return; + } else { + Object *ob = v3d->camera; + + float orig_ofs[3]; + float orig_dist=v3d->dist; + float orig_lens=v3d->lens; + float new_dist=0.0; + float new_lens=35.0; + float new_quat[4]; + float new_ofs[3]; + + VECCOPY(orig_ofs, v3d->ofs); + + view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens); + + v3d->persp= V3D_PERSP; + smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens); + VECCOPY(v3d->ofs, orig_ofs); + v3d->lens= orig_lens; + v3d->dist = orig_dist; /* restore the dist */ + + v3d->camera = ob; + v3d->persp= V3D_CAMOB; + } +} + + diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript index 7e591ad34f6..2d078988b9f 100644 --- a/source/blender/windowmanager/SConscript +++ b/source/blender/windowmanager/SConscript @@ -9,7 +9,7 @@ sources = env.Glob('intern/*.c') incs = '. ../editors/include ../python ../makesdna ../blenlib ../blenkernel' incs += ' ../nodes ../imbuf ../blenloader ../render/extern/include' incs += ' ../ftfont ../radiosity/extern/include ../../kernel/gen_system' -incs += ' ../makesrna' +incs += ' ../makesrna ../gpu' incs += ' #/intern/guardedalloc #/intern/memutil #/intern/ghost #/intern/bmfont' incs += ' #/intern/elbeem #/extern/glew/include' diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 3c8628c5fbb..222982fb05f 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -138,6 +138,8 @@ void wmFrustum (wmWindow *win, float x1, float x2, float y1, float y2, float void wmOrtho (wmWindow *win, float x1, float x2, float y1, float y2, float n, float f); void wmOrtho2 (wmWindow *win, float x1, float x2, float y1, float y2); + /* utilities */ +void WM_set_framebuffer_index_color(int index); #endif /* WM_API_H */ diff --git a/source/blender/windowmanager/intern/Makefile b/source/blender/windowmanager/intern/Makefile index 00412f00445..5ca68bef0a2 100644 --- a/source/blender/windowmanager/intern/Makefile +++ b/source/blender/windowmanager/intern/Makefile @@ -57,6 +57,7 @@ CPPFLAGS += -I../../blenkernel CPPFLAGS += -I../../nodes CPPFLAGS += -I../../imbuf CPPFLAGS += -I../../blenloader +CPPFLAGS += -I../../gpu CPPFLAGS += -I../../render/extern/include CPPFLAGS += -I../../ftfont CPPFLAGS += -I../../radiosity/extern/include diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index ae84ac26979..d8448be30ab 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -69,8 +69,6 @@ #include "SYS_System.h" -#include "UI_interface.h" - #include "RNA_define.h" #include "WM_api.h" @@ -84,6 +82,12 @@ #include "ED_screen.h" +#include "UI_interface.h" + +#include "GPU_extensions.h" +#include "GPU_draw.h" + + static void initbuttons(void) { UI_init(); @@ -135,7 +139,9 @@ void WM_init(bContext *C) // XXX UI_filelist_init_icons(); -// init_gl_stuff(); /* drawview.c, after homefile */ + GPU_state_init(); + GPU_extensions_init(); + read_Blog(); BLI_strncpy(G.lib, G.sce, FILE_MAX); } diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 56574829b53..7477cb35a6d 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -445,7 +445,7 @@ static unsigned int index_to_framebuffer(int index) #endif -void set_framebuffer_index_color(int index) +void WM_set_framebuffer_index_color(int index) { cpack(index_to_framebuffer(index)); } |