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! :)
This commit is contained in:
Ton Roosendaal
2008-12-19 12:14:58 +00:00
parent c752ec9fc4
commit d92b45d558
16 changed files with 8510 additions and 141 deletions

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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] )

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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 setwinmatrixview3d(wmWindow *win, View3D *v3d, int winx, int winy, rctf *rect); /* rect: for picking */
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(struct wmWindow *win, View3D *v3d, int winx, int winy, rctf *rect); /* rect: for picking */
void setviewmatrixview3d(View3D *v3d);
#endif /* ED_VIEW3D_INTERN_H */

View File

@@ -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;
}
}

View File

@@ -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'

View File

@@ -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 */

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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));
}