Fine control of feature edge selection with mesh face and edge marks.

New "face marks" and "edge marks" have been introduced in mesh data
blocks.  In the edit mode of a mesh object, face marks can be put
to selected faces by choosing Mesh >> Faces >> Mark Freestyle Face
from the menu of a 3D View window or Ctrl-F >> Mark Freestyle Face
from the context menu.  Similarly, edge marks can be put to selected
edges by Mesh >> Edges >> Mark Freestyle Edge or Ctrl-E >> Mark
Freestyle Edge.  These marks should work fine with the Subdivision
surface modifier.

Moreover, two new conditions for feature edge selection have been
added to the Parameter Editor mode as described below:

1. The Selection by Edge Types option has now the new Edge Mark type,
which can be used to (de)select feature edges having edge marks.
This option can be used to add to (or remove from) the view map
arbitrary edges of mesh objects.

2. Selection by Face Marks option has been newly introduced, in which
face marks are used for feature edge selection in two ways.  One
option is called "One Face" which is to (de)select feature edges if
one of faces on the left and right of each feature edge has a face
mark.  The other option is "Both Faces" to (de)select feature edges
if both faces on the left and right have a face mark.
This commit is contained in:
2011-10-06 02:04:43 +00:00
parent cb4f662927
commit f84e8e7640
45 changed files with 724 additions and 51 deletions

View File

@@ -752,6 +752,32 @@ class LengthThresholdUP1D(UnaryPredicate1D):
return False
return True
class FaceMarkBothUP1D(UnaryPredicate1D):
def __call__(self, inter): # ViewEdge
fe = inter.fedgeA()
while fe is not None:
if fe.isSmooth():
if fe.faceMark():
return True
else:
if fe.aFaceMark() and fe.bFaceMark():
return True
fe = fe.nextEdge()
return False
class FaceMarkOneUP1D(UnaryPredicate1D):
def __call__(self, inter): # ViewEdge
fe = inter.fedgeA()
while fe is not None:
if fe.isSmooth():
if fe.faceMark():
return True
else:
if fe.aFaceMark() or fe.bFaceMark():
return True
fe = fe.nextEdge()
return False
# predicates for splitting
class MaterialBoundaryUP0D(UnaryPredicate0D):
@@ -825,6 +851,8 @@ def process(layer_name, lineset_name):
flags |= Nature.SUGGESTIVE_CONTOUR
if lineset.select_material_boundary:
flags |= Nature.MATERIAL_BOUNDARY
if lineset.select_edge_mark:
flags |= Nature.EDGE_MARK
if flags != Nature.NO_FEATURE:
edge_type_criteria.append(pyNatureUP1D(flags))
else:
@@ -842,6 +870,8 @@ def process(layer_name, lineset_name):
edge_type_criteria.append(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR))
if lineset.select_material_boundary:
edge_type_criteria.append(pyNatureUP1D(Nature.MATERIAL_BOUNDARY))
if lineset.select_edge_mark:
edge_type_criteria.append(pyNatureUP1D(Nature.EDGE_MARK))
if lineset.select_contour:
edge_type_criteria.append(ContourUP1D())
if lineset.select_external_contour:
@@ -854,6 +884,15 @@ def process(layer_name, lineset_name):
if lineset.edge_type_negation == "EXCLUSIVE":
upred = NotUP1D(upred)
selection_criteria.append(upred)
# prepare selection criteria by face marks
if lineset.select_by_face_marks:
if lineset.face_mark_condition == "BOTH":
upred = FaceMarkBothUP1D()
else:
upred = FaceMarkOneUP1D()
if lineset.face_mark_negation == "EXCLUSIVE":
upred = NotUP1D(upred)
selection_criteria.append(upred)
# prepare selection criteria by group of objects
if lineset.select_by_group:
if lineset.group is not None and len(lineset.group.objects) > 0:

View File

@@ -253,11 +253,20 @@ class RENDER_PT_freestyle(RenderButtonsPanel, Panel):
sub.prop(lineset, "select_valley")
sub.prop(lineset, "select_suggestive_contour")
sub.prop(lineset, "select_material_boundary")
sub.prop(lineset, "select_edge_mark")
sub = row.column()
sub.prop(lineset, "select_contour")
sub.prop(lineset, "select_external_contour")
col.separator() # XXX
col.prop(lineset, "select_by_face_marks")
if lineset.select_by_face_marks:
row = col.row()
row.prop(lineset, "face_mark_negation", expand=True)
row = col.row()
row.prop(lineset, "face_mark_condition", expand=True)
col.separator() # XXX
col.prop(lineset, "select_by_group")
if lineset.select_by_group:
col.prop(lineset, "group")

View File

@@ -1605,6 +1605,11 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
layout.operator("mesh.mark_freestyle_edge")
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
layout.separator()
layout.operator("mesh.edge_rotate", text="Rotate Edge CW").direction = 'CW'
layout.operator("mesh.edge_rotate", text="Rotate Edge CCW").direction = 'CCW'
@@ -1647,6 +1652,11 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
layout.operator("mesh.mark_freestyle_face")
layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
layout.separator()
layout.operator("mesh.quads_convert_to_tris")
layout.operator("mesh.tris_convert_to_quads")
layout.operator("mesh.edge_flip")
@@ -2170,6 +2180,8 @@ class VIEW3D_PT_view3d_meshdisplay(Panel):
col.prop(mesh, "show_edge_bevel_weight", text="Bevel Weights")
col.prop(mesh, "show_edge_seams", text="Seams")
col.prop(mesh, "show_edge_sharp", text="Sharp")
col.prop(mesh, "show_freestyle_edge_marks", text="Freestyle Edge Marks")
col.prop(mesh, "show_freestyle_face_marks", text="Freestyle Face Marks")
col.separator()
col.label(text="Normals:")

View File

@@ -303,6 +303,7 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
e->flag = eed->f & SELECT;
if(eed->sharp) e->flag |= ME_SHARP;
if(eed->seam) e->flag |= ME_SEAM;
if(eed->freestyle) e->flag |= ME_FREESTYLE_EDGE;
//XXX if(eed->h & EM_FGON) e->flag |= ME_FGON;
if(eed->h & 1) e->flag |= ME_HIDE;
eed->tmp.e = (EditEdge*)e;
@@ -395,6 +396,7 @@ void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
eed->bweight = e->bweight;
if(e->flag & ME_SEAM) eed->seam = 1;
if(e->flag & ME_SHARP) eed->sharp = 1;
if(e->flag & ME_FREESTYLE_EDGE) eed->freestyle = 1;
if(e->flag & SELECT) eed->f |= SELECT;
//XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
if(e->flag & ME_HIDE) eed->h |= 1;

View File

@@ -1199,6 +1199,7 @@ static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
if (ee->seam) edge_r->flag |= ME_SEAM;
if (ee->sharp) edge_r->flag |= ME_SHARP;
if (ee->freestyle) edge_r->flag |= ME_FREESTYLE_EDGE;
#if 0
/* this needs setup of f2 field */
if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
@@ -1299,6 +1300,7 @@ static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
if (ee->seam) edge_r->flag |= ME_SEAM;
if (ee->sharp) edge_r->flag |= ME_SHARP;
if (ee->freestyle) edge_r->flag |= ME_FREESTYLE_EDGE;
#if 0
/* this needs setup of f2 field */
if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;

View File

@@ -1651,6 +1651,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
if(eed->seam) med->flag |= ME_SEAM;
if(eed->sharp) med->flag |= ME_SHARP;
if(eed->freestyle) med->flag |= ME_FREESTYLE_EDGE;
if(!eed->f2) med->flag |= ME_LOOSEEDGE;
*index = i;

View File

@@ -751,7 +751,7 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
edgeFlag = (ccgdm->edgeFlags)? &ccgdm->edgeFlags[i]: NULL;
if(edgeFlag)
flags |= (*edgeFlag & (ME_SEAM | ME_SHARP))
flags |= (*edgeFlag & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE))
| ME_EDGEDRAW | ME_EDGERENDER;
else
flags |= ME_EDGEDRAW | ME_EDGERENDER;
@@ -936,7 +936,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
if(edgeFlags) {
if(edgeIdx != -1) {
flags |= (edgeFlags[index] & (ME_SEAM | ME_SHARP))
flags |= (edgeFlags[index] & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE))
| ME_EDGEDRAW | ME_EDGERENDER;
}
} else {

View File

@@ -102,7 +102,7 @@ typedef struct EditEdge
float fp;
} tmp;
short f1, f2; /* short, f1 is (ab)used in subdiv */
unsigned char f, h, dir, seam, sharp;
unsigned char f, h, dir, seam, sharp, freestyle;
float crease;
float bweight;
short fast; /* only 0 or 1, for editmesh_fastmalloc */

View File

@@ -248,7 +248,10 @@ enum {
TH_DRAWEXTRA_FACEAREA,
TH_DRAWEXTRA_FACEANG,
TH_NODE_CURVING
TH_NODE_CURVING,
TH_FREESTYLE_EDGE_MARK,
TH_FREESTYLE_FACE_MARK
};
/* XXX WARNING: previous is saved in file, so do not change order! */

View File

@@ -344,6 +344,10 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp= ts->handle_sel_vect; break;
case TH_HANDLE_SEL_ALIGN:
cp= ts->handle_sel_align; break;
case TH_FREESTYLE_EDGE_MARK:
cp= ts->freestyle_edge_mark; break;
case TH_FREESTYLE_FACE_MARK:
cp= ts->freestyle_face_mark; break;
case TH_SYNTAX_B:
cp= ts->syntaxb; break;
@@ -621,6 +625,8 @@ void ui_theme_init_default(void)
SETCOL(btheme->tv3d.button_text_hi, 255, 255, 255, 255);
SETCOL(btheme->tv3d.button_title, 0, 0, 0, 255);
SETCOL(btheme->tv3d.title, 0, 0, 0, 255);
SETCOL(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
SETCOL(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
btheme->tv3d.facedot_size= 4;
@@ -1613,6 +1619,19 @@ void init_userdef_do_versions(void)
}
}
/* Freestyle color settings */
{
bTheme *btheme;
for(btheme= U.themes.first; btheme; btheme= btheme->next) {
/* check for alpha==0 is safe, then color was never set */
if(btheme->tv3d.freestyle_edge_mark[3]==0) {
SETCOL(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
SETCOL(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
}
}
}
/* GL Texture Garbage Collection (variable abused above!) */
if (U.textimeout == 0) {
U.texcollectrate = 60;

View File

@@ -502,6 +502,10 @@ void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
if (val) {eed->bweight = 1.0f;}
else {eed->bweight = 0.0f;}
break;
case EDGE_MODE_TAG_FREESTYLE:
if (val) {eed->freestyle = 1;}
else {eed->freestyle = 0;}
break;
}
}
@@ -518,6 +522,8 @@ int edgetag_context_check(Scene *scene, EditEdge *eed)
return eed->crease ? 1 : 0;
case EDGE_MODE_TAG_BEVEL:
return eed->bweight ? 1 : 0;
case EDGE_MODE_TAG_FREESTYLE:
return eed->freestyle ? 1 : 0;
}
return 0;
}

View File

@@ -259,6 +259,7 @@ EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *exampl
if(example) {
eed->crease= example->crease;
eed->bweight= example->bweight;
eed->freestyle = example->freestyle;
eed->sharp = example->sharp;
eed->seam = example->seam;
eed->h |= (example->h & EM_FGON);
@@ -828,6 +829,7 @@ void make_editMesh(Scene *scene, Object *ob)
if(medge->flag & ME_SEAM) eed->seam= 1;
if(medge->flag & ME_SHARP) eed->sharp = 1;
if(medge->flag & ME_FREESTYLE_EDGE) eed->freestyle = 1;
if(medge->flag & SELECT) eed->f |= SELECT;
if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
if(medge->flag & ME_HIDE) eed->h |= 1;
@@ -1023,6 +1025,7 @@ void load_editMesh(Scene *scene, Object *obedit)
if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
if(eed->sharp) medge->flag |= ME_SHARP;
if(eed->seam) medge->flag |= ME_SEAM;
if(eed->freestyle) medge->flag |= ME_FREESTYLE_EDGE;
if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
if(eed->h & 1) medge->flag |= ME_HIDE;
@@ -1578,7 +1581,7 @@ typedef struct EditVertC
typedef struct EditEdgeC
{
int v1, v2;
unsigned char f, h, seam, sharp, pad;
unsigned char f, h, seam, sharp, freestyle;
short crease, bweight, fgoni;
} EditEdgeC;
@@ -1680,6 +1683,7 @@ static void *editMesh_to_undoMesh(void *emv)
eedc->h= eed->h;
eedc->seam= eed->seam;
eedc->sharp= eed->sharp;
eedc->freestyle= eed->freestyle;
eedc->crease= (short)(eed->crease*255.0f);
eedc->bweight= (short)(eed->bweight*255.0f);
eedc->fgoni= eed->fgoni;
@@ -1778,6 +1782,7 @@ static void undoMesh_to_editMesh(void *umv, void *emv)
eed->h= eedc->h;
eed->seam= eedc->seam;
eed->sharp= eedc->sharp;
eed->freestyle= eedc->freestyle;
eed->fgoni= eedc->fgoni;
eed->crease= ((float)eedc->crease)/255.0f;
eed->bweight= ((float)eedc->bweight)/255.0f;

View File

@@ -702,6 +702,7 @@ static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed,
#define SIMEDGE_SEAM 106
#define SIMEDGE_SHARP 107
#define SIMEDGE_TOT 108
#define SIMEDGE_FREESTYLE 109
/* FACE GROUP */
@@ -724,6 +725,7 @@ static EnumPropertyItem prop_similar_types[] = {
{SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
{SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
{SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
{SIMEDGE_FREESTYLE, "FREESTYLE", 0, "Freestyle Edge Mark", ""},
{SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
{SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
{SIMFACE_AREA, "AREA", 0, "Area", ""},
@@ -1076,6 +1078,20 @@ static int similar_edge_select__internal(EditMesh *em, int mode, float thresh)
return selcount;
}
}
} else if (mode==SIMEDGE_FREESTYLE) { /* Freestyle edge mark */
for(eed= em->edges.first; eed; eed= eed->next) {
if (
!(eed->f & SELECT) &&
!eed->h &&
(eed->freestyle == base_eed->freestyle)
) {
EM_select_edge(eed, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
}
}
}
@@ -2220,6 +2236,9 @@ static void mouse_mesh_shortest_path(bContext *C, const int mval[2])
case EDGE_MODE_TAG_BEVEL:
me->drawflag |= ME_DRAWBWEIGHTS;
break;
case EDGE_MODE_TAG_FREESTYLE:
me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
break;
}
/* live unwrap while tagging */
@@ -3861,6 +3880,58 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
}
static int editmesh_mark_freestyle_edge(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
Mesh *me= ((Mesh *)obedit->data);
int clear = RNA_boolean_get(op->ptr, "clear");
EditEdge *eed;
/* auto-enable Freestyle edge mark drawing */
if(!clear) {
me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
}
if(!clear) {
eed= em->edges.first;
while(eed) {
if(!eed->h && (eed->f & SELECT)) eed->freestyle = 1;
eed = eed->next;
}
} else {
eed= em->edges.first;
while(eed) {
if(!eed->h && (eed->f & SELECT)) eed->freestyle = 0;
eed = eed->next;
}
}
BKE_mesh_end_editmesh(obedit->data, em);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
return OPERATOR_FINISHED;
}
void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mark Freestyle Edge";
ot->description= "(un)mark selected edges as Freestyle feature edges";
ot->idname= "MESH_OT_mark_freestyle_edge";
/* api callbacks */
ot->exec= editmesh_mark_freestyle_edge;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
}
/* **************** NORMALS ************** */
void EM_recalc_normal_direction(EditMesh *em, int inside, int select) /* makes faces righthand turning */

View File

@@ -3775,6 +3775,7 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
srchedge->h = eed->h;
srchedge->dir = eed->dir;
srchedge->seam = eed->seam;
srchedge->freestyle = eed->freestyle;
srchedge->crease = eed->crease;
srchedge->bweight = eed->bweight;
}
@@ -7604,3 +7605,54 @@ void MESH_OT_select_axis(wmOperatorType *ot)
RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
}
/********************** Freestyle Face Mark Operator *************************/
static int mesh_mark_freestyle_face_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
Mesh *me= ((Mesh *)obedit->data);
int clear = RNA_boolean_get(op->ptr, "clear");
EditFace *efa;
/* auto-enable Freestyle face mark drawing */
if(!clear) {
me->drawflag |= ME_DRAW_FREESTYLE_FACE;
}
if(!clear) {
for(efa= em->faces.first; efa; efa=efa->next) {
if(efa->f & SELECT)
efa->flag |= ME_FREESTYLE_FACE;
}
} else {
for(efa= em->faces.first; efa; efa=efa->next) {
if(efa->f & SELECT)
efa->flag &= ~ME_FREESTYLE_FACE;
}
}
BKE_mesh_end_editmesh(obedit->data, em);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
return OPERATOR_FINISHED;
}
void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mark Freestyle Face";
ot->description= "(un)mark selected faces for exclusion from Freestyle feature edge detection";
ot->idname= "MESH_OT_mark_freestyle_face";
/* api callbacks */
ot->exec= mesh_mark_freestyle_face_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
}

View File

@@ -162,6 +162,7 @@ void MESH_OT_select_random(struct wmOperatorType *ot);
void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
void MESH_OT_mark_seam(struct wmOperatorType *ot);
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_noise(struct wmOperatorType *ot);
void MESH_OT_flip_normals(struct wmOperatorType *ot);
@@ -242,6 +243,7 @@ void MESH_OT_rip(struct wmOperatorType *ot);
void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot);
void MESH_OT_blend_from_shape(struct wmOperatorType *ot);
void MESH_OT_sort_faces(struct wmOperatorType *ot);
void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
/* ******************* mesh_data.c */

View File

@@ -118,6 +118,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
WM_operatortype_append(MESH_OT_sort_faces);
WM_operatortype_append(MESH_OT_mark_freestyle_face);
WM_operatortype_append(MESH_OT_delete);
@@ -130,6 +131,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
WM_operatortype_append(MESH_OT_mark_sharp);
WM_operatortype_append(MESH_OT_mark_freestyle_edge);
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_noise);
WM_operatortype_append(MESH_OT_flip_normals);

View File

@@ -2098,21 +2098,32 @@ static void draw_dm_edges_sharp(DerivedMesh *dm)
dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
}
/* Draw only Freestyle feature edges */
static int draw_dm_edges_freestyle__setDrawOptions(void *UNUSED(userData), int index)
{
EditEdge *eed = EM_get_edge_for_index(index);
return (eed->h==0 && eed->freestyle);
}
static void draw_dm_edges_freestyle(DerivedMesh *dm)
{
dm->drawMappedEdges(dm, draw_dm_edges_freestyle__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 *UNUSED(drawSmooth_r))
{
struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
struct { unsigned char *cols[4]; 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]);
glColor4ubv(data->cols[3]);
return 2; /* stipple */
} else {
col = data->cols[(efa->f&SELECT)?1:0];
col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
if (col[3]==0) return 0;
glColor4ubv(col);
return 1;
@@ -2123,7 +2134,7 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNU
static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
{
struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
struct { unsigned char *cols[4]; EditFace *efa_act; } * data = userData;
EditFace *efa = EM_get_face_for_index(index);
EditFace *next_efa = EM_get_face_for_index(next_index);
unsigned char *col, *next_col;
@@ -2134,8 +2145,8 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
if(efa == data->efa_act || next_efa == data->efa_act)
return 0;
col = data->cols[(efa->f&SELECT)?1:0];
next_col = data->cols[(next_efa->f&SELECT)?1:0];
col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
next_col = data->cols[(next_efa->f & SELECT) ? 1 : (next_efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
if(col[3]==0 || next_col[3]==0)
return 0;
@@ -2144,12 +2155,13 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
}
/* 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)
static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, EditFace *efa_act)
{
struct { unsigned char *cols[3]; EditFace *efa_act; } data;
struct { unsigned char *cols[4]; EditFace *efa_act; } data;
data.cols[0] = baseCol;
data.cols[1] = selCol;
data.cols[2] = actCol;
data.cols[2] = markCol;
data.cols[3] = actCol;
data.efa_act = efa_act;
dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions);
@@ -2583,11 +2595,12 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
}
if(me->drawflag & ME_DRAWFACES) { /* transp faces */
unsigned char col1[4], col2[4], col3[4];
unsigned char col1[4], col2[4], col3[4], col4[4];
UI_GetThemeColor4ubv(TH_FACE, col1);
UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col3);
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col4);
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
@@ -2596,7 +2609,10 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
if CHECK_OB_DRAWTEXTURE(v3d, dt)
col1[3] = 0;
draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE))
col3[3] = 0;
draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2604,14 +2620,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
/* 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, col3);
unsigned char col1[4], col2[4], col3[4], col4[4];
col1[3] = col2[3] = col3[3] = 0; /* dont draw */
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col4);
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2646,6 +2662,16 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glLineWidth(1);
}
if(me->drawflag & ME_DRAW_FREESTYLE_EDGE) {
UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
glLineWidth(2);
draw_dm_edges_freestyle(cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
}
if(me->drawflag & ME_DRAWCREASES) {
draw_dm_creases(cageDM);
}

View File

@@ -125,37 +125,47 @@ void BlenderFileLoader::clipLine(float v1[3], float v2[3], float c[3], float z)
// obtain a set of vertices after the clipping. The number of vertices
// is at most 5.
void BlenderFileLoader::clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3],
float triNormals[][3], float n1[3], float n2[3], float n3[3], int clip[3])
float triNormals[][3], float n1[3], float n2[3], float n3[3],
bool edgeMarks[], bool em1, bool em2, bool em3, int clip[3])
{
float *v[3], *n[3];
bool em[3];
int i, j, k;
v[0] = v1; n[0] = n1;
v[1] = v2; n[1] = n2;
v[2] = v3; n[2] = n3;
em[0] = em1; /* edge mark of the edge between v1 and v2 */
em[1] = em2; /* edge mark of the edge between v2 and v3 */
em[2] = em3; /* edge mark of the edge between v3 and v1 */
k = 0;
for (i = 0; i < 3; i++) {
j = (i + 1) % 3;
if (clip[i] == NOT_CLIPPED) {
copy_v3_v3(triCoords[k], v[i]);
copy_v3_v3(triNormals[k], n[i]);
edgeMarks[k] = em[i];
k++;
if (clip[j] != NOT_CLIPPED) {
clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
copy_v3_v3(triNormals[k], n[j]);
edgeMarks[k] = false;
k++;
}
} else if (clip[i] != clip[j]) {
if (clip[j] == NOT_CLIPPED) {
clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
copy_v3_v3(triNormals[k], n[i]);
edgeMarks[k] = em[i];
k++;
} else {
clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
copy_v3_v3(triNormals[k], n[i]);
edgeMarks[k] = em[i];
k++;
clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
copy_v3_v3(triNormals[k], n[j]);
edgeMarks[k] = false;
k++;
}
}
@@ -164,10 +174,12 @@ void BlenderFileLoader::clipTriangle(int numTris, float triCoords[][3], float v1
}
void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
float n1[3], float n2[3], float n3[3])
float n1[3], float n2[3], float n3[3],
bool fm, bool em1, bool em2, bool em3)
{
float *fv[3], *fn[3], len;
unsigned i, j;
IndexedFaceSet::FaceEdgeMark marks = 0;
// initialize the bounding box by the first vertex
if (ls->currentIndex == 0) {
@@ -209,6 +221,11 @@ void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v
ls->pni++;
ls->pmi++;
}
if (fm) marks |= IndexedFaceSet::FACE_MARK;
if (em1) marks |= IndexedFaceSet::EDGE_MARK_V1V2;
if (em2) marks |= IndexedFaceSet::EDGE_MARK_V2V3;
if (em3) marks |= IndexedFaceSet::EDGE_MARK_V3V1;
*ls->pm++ = marks;
}
void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
@@ -272,6 +289,8 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
faceStyle[i] = IndexedFaceSet::TRIANGLES;
numVertexPerFaces[i] = 3;
}
IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
unsigned viSize = 3*numFaces;
unsigned *VIndices = new unsigned[viSize];
@@ -282,6 +301,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
struct LoaderState ls;
ls.pv = vertices;
ls.pn = normals;
ls.pm = faceEdgeMarks;
ls.pvi = VIndices;
ls.pni = NIndices;
ls.pmi = MIndices;
@@ -339,6 +359,17 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
numTris_2 = (vlr->v4) ? countClippedFaces(v1, v3, v4, clip_2) : 0;
if (numTris_1 == 0 && numTris_2 == 0)
continue;
bool fm, em1, em2, em3, em4;
fm = (vlr->flag & ME_FREESTYLE_FACE) != 0;
em1= (vlr->freestyle_edge_mark & R_EDGE_V1V2) != 0;
em2= (vlr->freestyle_edge_mark & R_EDGE_V2V3) != 0;
if (!vlr->v4) {
em3= (vlr->freestyle_edge_mark & R_EDGE_V3V1) != 0;
em4= false;
} else {
em3= (vlr->freestyle_edge_mark & R_EDGE_V3V4) != 0;
em4= (vlr->freestyle_edge_mark & R_EDGE_V4V1) != 0;
}
Material *mat = vlr->mat;
@@ -379,21 +410,28 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
}
float triCoords[5][3], triNormals[5][3];
bool edgeMarks[5]; // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
if (numTris_1 > 0) {
clipTriangle(numTris_1, triCoords, v1, v2, v3, triNormals, n1, n2, n3, clip_1);
clipTriangle(numTris_1, triCoords, v1, v2, v3, triNormals, n1, n2, n3,
edgeMarks, em1, em2, (!vlr->v4) ? em3 : false, clip_1);
for (i = 0; i < numTris_1; i++) {
addTriangle(&ls, triCoords[0], triCoords[i+1], triCoords[i+2],
triNormals[0], triNormals[i+1], triNormals[i+2]);
triNormals[0], triNormals[i+1], triNormals[i+2],
fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i+1],
(i == numTris_1 - 1) ? edgeMarks[i+2] : false);
_numFacesRead++;
}
}
if (numTris_2 > 0) {
clipTriangle(numTris_2, triCoords, v1, v3, v4, triNormals, n1, n3, n4, clip_2);
clipTriangle(numTris_2, triCoords, v1, v3, v4, triNormals, n1, n3, n4,
edgeMarks, false, em3, em4, clip_2);
for (i = 0; i < numTris_2; i++) {
addTriangle(&ls, triCoords[0], triCoords[i+1], triCoords[i+2],
triNormals[0], triNormals[i+1], triNormals[i+2]);
triNormals[0], triNormals[i+1], triNormals[i+2],
fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i+1],
(i == numTris_2 - 1) ? edgeMarks[i+2] : false);
_numFacesRead++;
}
}
@@ -444,6 +482,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
marray, meshFrsMaterials.size(),
0, 0,
numFaces, numVertexPerFaces, faceStyle,
faceEdgeMarks,
cleanVIndices, viSize,
cleanNIndices, niSize,
MIndices, viSize,

View File

@@ -18,6 +18,7 @@ extern "C" {
#endif
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "render_types.h"
#include "renderdatabase.h"
@@ -36,6 +37,7 @@ class NodeGroup;
struct LoaderState {
float *pv;
float *pn;
IndexedFaceSet::FaceEdgeMark *pm;
unsigned *pvi;
unsigned *pni;
unsigned *pmi;
@@ -66,9 +68,10 @@ protected:
int countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3]);
void clipLine(float v1[3], float v2[3], float c[3], float z);
void clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3],
float triNormals[][3], float n1[3], float n2[3], float n3[3], int clip[3]);
float triNormals[][3], float n1[3], float n2[3], float n3[3],
bool edgeMarks[5], bool em1, bool em2, bool em3, int clip[3]);
void addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
float n1[3], float n2[3], float n3[3]);
float n1[3], float n2[3], float n3[3], bool fm, bool em1, bool em2, bool em3);
protected:
Render* _re;

View File

@@ -78,7 +78,8 @@ static char Nature___doc__[] =
"* Nature.RIDGE: True for ridges.\n"
"* Nature.VALLEY: True for valleys.\n"
"* Nature.SUGGESTIVE_CONTOUR: True for suggestive contours.\n"
"* Nature.MATERIAL_BOUNDARY: True for edges at material boundaries.\n";
"* Nature.MATERIAL_BOUNDARY: True for edges at material boundaries.\n"
"* Nature.EDGE_MARK: True for edges having user-defined edge marks.\n";
/*-----------------------BPy_Nature type definition ------------------------------*/
@@ -181,6 +182,10 @@ static PyLongObject _Nature_MATERIAL_BOUNDARY = {
PyVarObject_HEAD_INIT(&Nature_Type, 1)
{ Nature::MATERIAL_BOUNDARY }
};
static PyLongObject _Nature_EDGE_MARK = {
PyVarObject_HEAD_INIT(&Nature_Type, 1)
{ Nature::EDGE_MARK }
};
#define BPy_Nature_POINT ((PyObject *)&_Nature_POINT)
#define BPy_Nature_S_VERTEX ((PyObject *)&_Nature_S_VERTEX)
@@ -196,6 +201,7 @@ static PyLongObject _Nature_MATERIAL_BOUNDARY = {
#define BPy_Nature_VALLEY ((PyObject *)&_Nature_VALLEY)
#define BPy_Nature_SUGGESTIVE_CONTOUR ((PyObject *)&_Nature_SUGGESTIVE_CONTOUR)
#define BPy_Nature_MATERIAL_BOUNDARY ((PyObject *)&_Nature_MATERIAL_BOUNDARY)
#define BPy_Nature_EDGE_MARK ((PyObject *)&_Nature_EDGE_MARK)
//-------------------MODULE INITIALIZATION--------------------------------
int Nature_Init( PyObject *module )
@@ -225,6 +231,7 @@ int Nature_Init( PyObject *module )
PyDict_SetItemString( Nature_Type.tp_dict, "VALLEY", BPy_Nature_VALLEY );
PyDict_SetItemString( Nature_Type.tp_dict, "SUGGESTIVE_CONTOUR", BPy_Nature_SUGGESTIVE_CONTOUR );
PyDict_SetItemString( Nature_Type.tp_dict, "MATERIAL_BOUNDARY", BPy_Nature_MATERIAL_BOUNDARY );
PyDict_SetItemString( Nature_Type.tp_dict, "EDGE_MARK", BPy_Nature_EDGE_MARK );
return 0;
}

View File

@@ -154,6 +154,32 @@ static PyObject * FEdgeSharp_bMaterial( BPy_FEdgeSharp *self ) {
return BPy_FrsMaterial_from_FrsMaterial(m);
}
static char FEdgeSharp_aFaceMark___doc__[] =
".. method:: aFaceMark()\n"
"\n"
" Returns the face mark of the face lying on the right of the FEdge.\n"
" If this FEdge is a border, it has no face on the right, and thus\n"
" false is returned.\n"
"\n"
" :return: The face mark of the face lying on the right of the FEdge.\n"
" :rtype: bool\n";
static PyObject * FEdgeSharp_aFaceMark( BPy_FEdgeSharp *self ) {
return PyBool_from_bool( self->fes->aFaceMark() );
}
static char FEdgeSharp_bFaceMark___doc__[] =
".. method:: bFaceMark()\n"
"\n"
" Returns the face mark of the face lying on the left of the FEdge.\n"
"\n"
" :return: The face mark of the face lying on the left of the FEdge.\n"
" :rtype: bool\n";
static PyObject * FEdgeSharp_bFaceMark( BPy_FEdgeSharp *self ) {
return PyBool_from_bool( self->fes->bFaceMark() );
}
static char FEdgeSharp_setNormalA___doc__[] =
".. method:: setNormalA(iNormal)\n"
"\n"
@@ -240,6 +266,44 @@ static PyObject * FEdgeSharp_setbMaterialIndex( BPy_FEdgeSharp *self, PyObject *
Py_RETURN_NONE;
}
static char FEdgeSharp_setaFaceMark___doc__[] =
".. method:: setaFaceMark(i)\n"
"\n"
" Sets the face mark of the face lying on the right of the FEdge.\n"
"\n"
" :arg i: A face mark.\n"
" :type i: bool\n";
static PyObject * FEdgeSharp_setaFaceMark( BPy_FEdgeSharp *self, PyObject *args ) {
PyObject *obj;
if(!( PyArg_ParseTuple(args, "O", &obj) ))
return NULL;
self->fes->setaFaceMark( bool_from_PyBool(obj) );
Py_RETURN_NONE;
}
static char FEdgeSharp_setbFaceMark___doc__[] =
".. method:: setbFaceMark(i)\n"
"\n"
" Sets the face mark of the face lying on the left of the FEdge.\n"
"\n"
" :arg i: A face mark.\n"
" :type i: bool\n";
static PyObject * FEdgeSharp_setbFaceMark( BPy_FEdgeSharp *self, PyObject *args ) {
PyObject *obj;
if(!( PyArg_ParseTuple(args, "O", &obj) ))
return NULL;
self->fes->setbFaceMark( bool_from_PyBool(obj) );
Py_RETURN_NONE;
}
/*----------------------FEdgeSharp instance definitions ----------------------------*/
static PyMethodDef BPy_FEdgeSharp_methods[] = {
{"normalA", ( PyCFunction ) FEdgeSharp_normalA, METH_NOARGS, FEdgeSharp_normalA___doc__},
@@ -248,10 +312,14 @@ static PyMethodDef BPy_FEdgeSharp_methods[] = {
{"bMaterialIndex", ( PyCFunction ) FEdgeSharp_bMaterialIndex, METH_NOARGS, FEdgeSharp_bMaterialIndex___doc__},
{"aMaterial", ( PyCFunction ) FEdgeSharp_aMaterial, METH_NOARGS, FEdgeSharp_aMaterial___doc__},
{"bMaterial", ( PyCFunction ) FEdgeSharp_bMaterial, METH_NOARGS, FEdgeSharp_bMaterial___doc__},
{"aFaceMark", ( PyCFunction ) FEdgeSharp_aFaceMark, METH_NOARGS, FEdgeSharp_aFaceMark___doc__},
{"bFaceMark", ( PyCFunction ) FEdgeSharp_bFaceMark, METH_NOARGS, FEdgeSharp_bFaceMark___doc__},
{"setNormalA", ( PyCFunction ) FEdgeSharp_setNormalA, METH_VARARGS, FEdgeSharp_setNormalA___doc__},
{"setNormalB", ( PyCFunction ) FEdgeSharp_setNormalB, METH_VARARGS, FEdgeSharp_setNormalB___doc__},
{"setaMaterialIndex", ( PyCFunction ) FEdgeSharp_setaMaterialIndex, METH_VARARGS, FEdgeSharp_setaMaterialIndex___doc__},
{"setbMaterialIndex", ( PyCFunction ) FEdgeSharp_setbMaterialIndex, METH_VARARGS, FEdgeSharp_setbMaterialIndex___doc__},
{"setaFaceMark", ( PyCFunction ) FEdgeSharp_setaFaceMark, METH_NOARGS, FEdgeSharp_setaFaceMark___doc__},
{"setbFaceMark", ( PyCFunction ) FEdgeSharp_setbFaceMark, METH_NOARGS, FEdgeSharp_setbFaceMark___doc__},
{NULL, NULL, 0, NULL}
};

View File

@@ -104,6 +104,18 @@ static PyObject * FEdgeSmooth_material( BPy_FEdgeSmooth *self ) {
return BPy_FrsMaterial_from_FrsMaterial(m);
}
static char FEdgeSmooth_faceMark___doc__[] =
".. method:: faceMark()\n"
"\n"
" Returns the face mark of the face it is running across.\n"
"\n"
" :return: The face mark of the face it is running across.\n"
" :rtype: bool\n";
static PyObject * FEdgeSmooth_faceMark( BPy_FEdgeSmooth *self ) {
return PyBool_from_bool( self->fes->faceMark() );
}
static char FEdgeSmooth_setNormal___doc__[] =
".. method:: setNormal(iNormal)\n"
"\n"
@@ -147,13 +159,34 @@ static PyObject * FEdgeSmooth_setMaterialIndex( BPy_FEdgeSmooth *self, PyObject
Py_RETURN_NONE;
}
static char FEdgeSmooth_setFaceMark___doc__[] =
".. method:: setFaceMark(i)\n"
"\n"
" Sets the face mark of the face it is running across.\n"
"\n"
" :arg i: A face mark.\n"
" :type i: bool\n";
static PyObject * FEdgeSmooth_setFaceMark( BPy_FEdgeSmooth *self, PyObject *args ) {
PyObject *obj;
if(!( PyArg_ParseTuple(args, "O", &obj) ))
return NULL;
self->fes->setFaceMark( bool_from_PyBool(obj) );
Py_RETURN_NONE;
}
/*----------------------FEdgeSmooth instance definitions ----------------------------*/
static PyMethodDef BPy_FEdgeSmooth_methods[] = {
{"normal", ( PyCFunction ) FEdgeSmooth_normal, METH_NOARGS, FEdgeSmooth_normal___doc__},
{"materialIndex", ( PyCFunction ) FEdgeSmooth_materialIndex, METH_NOARGS, FEdgeSmooth_materialIndex___doc__},
{"material", ( PyCFunction ) FEdgeSmooth_material, METH_NOARGS, FEdgeSmooth_material___doc__},
{"faceMark", ( PyCFunction ) FEdgeSmooth_faceMark, METH_NOARGS, FEdgeSmooth_faceMark___doc__},
{"setNormal", ( PyCFunction ) FEdgeSmooth_setNormal, METH_VARARGS, FEdgeSmooth_setNormal___doc__},
{"setMaterialIndex", ( PyCFunction ) FEdgeSmooth_setMaterialIndex, METH_VARARGS, FEdgeSmooth_setMaterialIndex___doc__},
{"setFaceMark", ( PyCFunction ) FEdgeSmooth_setFaceMark, METH_VARARGS, FEdgeSmooth_setFaceMark___doc__},
{NULL, NULL, 0, NULL}
};

View File

@@ -28,6 +28,7 @@ IndexedFaceSet::IndexedFaceSet()
_Normals = NULL;
_FrsMaterials = 0;
_TexCoords = 0;
_FaceEdgeMarks = 0;
_VSize = 0;
_NSize = 0;
_MSize = 0;
@@ -51,6 +52,7 @@ IndexedFaceSet::IndexedFaceSet( real *iVertices, unsigned iVSize,
FrsMaterial **iMaterials, unsigned iMSize,
real *iTexCoords, unsigned iTSize,
unsigned iNumFaces, unsigned *iNumVertexPerFace, TRIANGLES_STYLE *iFaceStyle,
FaceEdgeMark *iFaceEdgeMarks,
unsigned *iVIndices, unsigned iVISize,
unsigned *iNIndices, unsigned iNISize,
unsigned *iMIndices, unsigned iMISize,
@@ -89,6 +91,9 @@ IndexedFaceSet::IndexedFaceSet( real *iVertices, unsigned iVSize,
_FaceStyle = new TRIANGLES_STYLE[_NumFaces];
memcpy(_FaceStyle, iFaceStyle, _NumFaces*sizeof(TRIANGLES_STYLE));
_FaceEdgeMarks = new FaceEdgeMark[_NumFaces];
memcpy(_FaceEdgeMarks, iFaceEdgeMarks, _NumFaces*sizeof(FaceEdgeMark));
_VISize = iVISize;
_VIndices = new unsigned[_VISize];
memcpy(_VIndices, iVIndices, _VISize*sizeof(unsigned));
@@ -129,6 +134,7 @@ IndexedFaceSet::IndexedFaceSet( real *iVertices, unsigned iVSize,
_NumFaces = iNumFaces;
_NumVertexPerFace = iNumVertexPerFace;
_FaceStyle = iFaceStyle;
_FaceEdgeMarks = iFaceEdgeMarks;
_VISize = iVISize;
_VIndices = iVIndices;
@@ -182,6 +188,9 @@ IndexedFaceSet::IndexedFaceSet( const IndexedFaceSet& iBrother)
_FaceStyle = new TRIANGLES_STYLE[_NumFaces];
memcpy(_FaceStyle, iBrother.trianglesStyle(), _NumFaces*sizeof(TRIANGLES_STYLE));
_FaceEdgeMarks = new FaceEdgeMark[_NumFaces];
memcpy(_FaceEdgeMarks, iBrother.faceEdgeMarks(), _NumFaces*sizeof(FaceEdgeMark));
_VISize = iBrother.visize();
_VIndices = new unsigned[_VISize];
@@ -249,6 +258,12 @@ IndexedFaceSet::~IndexedFaceSet()
_FaceStyle = NULL;
}
if(NULL != _FaceEdgeMarks)
{
delete [] _FaceEdgeMarks;
_FaceEdgeMarks = NULL;
}
if(NULL != _VIndices)
{
delete [] _VIndices;

View File

@@ -45,6 +45,13 @@ public:
/*! Triangles description style:*/
enum TRIANGLES_STYLE{TRIANGLE_STRIP, TRIANGLE_FAN, TRIANGLES};
/*! User-specified face and edge marks for feature edge detection */
typedef unsigned char FaceEdgeMark;
static const FaceEdgeMark FACE_MARK = 1;
static const FaceEdgeMark EDGE_MARK_V1V2 = 2;
static const FaceEdgeMark EDGE_MARK_V2V3 = 4;
static const FaceEdgeMark EDGE_MARK_V3V1 = 8;
/*! Builds an empty indexed face set
*/
IndexedFaceSet();
@@ -109,6 +116,7 @@ public:
FrsMaterial **iMaterials, unsigned iMSize,
real *iTexCoords, unsigned iTSize,
unsigned iNumFaces, unsigned *iNumVertexPerFace, TRIANGLES_STYLE *iFaceStyle,
FaceEdgeMark *iFaceEdgeMarks,
unsigned *iVIndices, unsigned iVISize,
unsigned *iNIndices, unsigned iNISize,
unsigned *iMIndices, unsigned iMISize,
@@ -124,6 +132,7 @@ public:
std::swap(_Normals, ioOther._Normals);
std::swap(_FrsMaterials, ioOther._FrsMaterials);
std::swap(_TexCoords, ioOther._TexCoords);
std::swap(_FaceEdgeMarks, ioOther._FaceEdgeMarks);
std::swap(_VSize, ioOther._VSize);
std::swap(_NSize, ioOther._NSize);
@@ -180,6 +189,7 @@ public:
virtual const unsigned numFaces() const {return _NumFaces;}
virtual const unsigned * numVertexPerFaces() const {return _NumVertexPerFace;}
virtual const TRIANGLES_STYLE * trianglesStyle() const {return _FaceStyle;}
virtual const unsigned char * faceEdgeMarks() const {return _FaceEdgeMarks;}
virtual const unsigned* vindices() const {return _VIndices;}
virtual const unsigned* nindices() const {return _NIndices;}
virtual const unsigned* mindices() const {return _MIndices;}
@@ -204,6 +214,7 @@ protected:
unsigned _NumFaces;
unsigned *_NumVertexPerFace;
TRIANGLES_STYLE *_FaceStyle;
FaceEdgeMark *_FaceEdgeMarks;
unsigned *_VIndices;
unsigned *_NIndices;

View File

@@ -72,6 +72,7 @@ void FEdgeXDetector::processShapes(WingedEdge& we) {
if(_computeSuggestiveContours)
processSuggestiveContourShape(wxs);
processSilhouetteShape(wxs);
processEdgeMarksShape(wxs);
if (progressBarDisplay)
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
@@ -708,6 +709,26 @@ void FEdgeXDetector::ProcessMaterialBoundaryEdge(WXEdge *iEdge)
}
}
// EDGE MARKS
/////////////
void FEdgeXDetector::processEdgeMarksShape(WXShape* iShape) {
// Make a pass on the edges to detect material boundaries
vector<WEdge*>::iterator we, weend;
vector<WEdge*> &wedges = iShape->getEdgeList();
for(we=wedges.begin(), weend=wedges.end();
we!=weend;
++we){
ProcessEdgeMarks((WXEdge*)(*we));
}
}
void FEdgeXDetector::ProcessEdgeMarks(WXEdge *iEdge) {
if (iEdge->GetMark()) {
iEdge->AddNature(Nature::EDGE_MARK);
}
}
// Build Smooth edges
/////////////////////
void FEdgeXDetector::buildSmoothEdges(WXShape* iShape){

View File

@@ -127,6 +127,10 @@ public:
virtual void processMaterialBoundaryShape(WXShape* iWShape);
virtual void ProcessMaterialBoundaryEdge(WXEdge *iEdge);
// EDGE MARKS
virtual void processEdgeMarksShape(WXShape* iShape);
virtual void ProcessEdgeMarks(WXEdge *iEdge);
// EVERYBODY
virtual void buildSmoothEdges(WXShape* iShape);
@@ -142,6 +146,12 @@ public:
_changes=true;
}
}
inline void enableFaceMarks(bool b) {
if (b != _faceMarks) {
_faceMarks = b;
_changes=true;
}
}
/*! Sets the radius of the geodesic sphere around each vertex (for the curvature computation)
* \param r
* The radius of the sphere expressed as a ratio of the mean edge size
@@ -175,6 +185,7 @@ protected:
bool _computeSuggestiveContours;
bool _computeMaterialBoundaries;
bool _faceSmoothness;
bool _faceMarks;
real _sphereRadius; // expressed as a ratio of the mean edge size
real _creaseAngle; // [-1, 1] compared with the inner product of face normals
bool _changes;

View File

@@ -798,6 +798,8 @@ protected:
Vec3r _bNormal; // When following the edge, normal of the left face
unsigned _aFrsMaterialIndex;
unsigned _bFrsMaterialIndex;
bool _aFaceMark;
bool _bFaceMark;
public:
/*! Returns the string "FEdgeSharp" . */
@@ -807,10 +809,12 @@ public:
/*! Default constructor. */
inline FEdgeSharp() : FEdge(){
_aFrsMaterialIndex = _bFrsMaterialIndex = 0;
_aFaceMark = _bFaceMark = false;
}
/*! Builds an FEdgeSharp going from vA to vB. */
inline FEdgeSharp(SVertex *vA, SVertex *vB) : FEdge(vA, vB){
_aFrsMaterialIndex = _bFrsMaterialIndex = 0;
_aFaceMark = _bFaceMark = false;
}
/*! Copy constructor. */
inline FEdgeSharp(FEdgeSharp& iBrother) : FEdge(iBrother){
@@ -818,6 +822,9 @@ public:
_bNormal = iBrother._bNormal;
_aFrsMaterialIndex = iBrother._aFrsMaterialIndex;
_bFrsMaterialIndex = iBrother._bFrsMaterialIndex;
_aFaceMark = iBrother._aFaceMark;
_bFaceMark = iBrother._bFaceMark;
}
/*! Destructor. */
virtual ~FEdgeSharp() {}
@@ -853,6 +860,12 @@ public:
* left of the FEdge.
*/
const FrsMaterial& bFrsMaterial() const ;
/*! Returns the face mark of the face lying on the right of the FEdge.
* If this FEdge is a border, it has no Face on its right and thus
* false is returned. */
inline bool aFaceMark() const {return _aFaceMark;}
/*! Returns the face mark of the face lying on the left of the FEdge. */
inline bool bFaceMark() const {return _bFaceMark;}
/*! Sets the normal to the face lying on the right of the FEdge. */
inline void setNormalA(const Vec3r& iNormal) {_aNormal = iNormal;}
@@ -862,6 +875,10 @@ public:
inline void setaFrsMaterialIndex(unsigned i) {_aFrsMaterialIndex = i;}
/*! Sets the index of the material lying on the left of the FEdge.*/
inline void setbFrsMaterialIndex(unsigned i) {_bFrsMaterialIndex = i;}
/*! Sets the face mark of the face lying on the right of the FEdge. */
inline void setaFaceMark(bool iFaceMark) {_aFaceMark = iFaceMark;}
/*! Sets the face mark of the face lying on the left of the FEdge. */
inline void setbFaceMark(bool iFaceMark) {_bFaceMark = iFaceMark;}
};
@@ -879,6 +896,7 @@ protected:
// Vec3r _VisibilityPointB; // using its 2 extremity points A and B
void * _Face; // In case of exact silhouette, Face is the WFace crossed by Fedge
// NON GERE PAR LE COPY CONSTRUCTEUR
bool _FaceMark;
public:
/*! Returns the string "FEdgeSmooth" . */
virtual string getExactTypeName() const {
@@ -887,12 +905,14 @@ public:
/*! Default constructor. */
inline FEdgeSmooth() : FEdge(){
_Face=0;
_FaceMark = false;
_FrsMaterialIndex = 0;
_isSmooth = true;
}
/*! Builds an FEdgeSmooth going from vA to vB. */
inline FEdgeSmooth(SVertex *vA, SVertex *vB) : FEdge(vA, vB){
_Face=0;
_FaceMark = false;
_FrsMaterialIndex = 0;
_isSmooth = true;
@@ -901,6 +921,7 @@ public:
inline FEdgeSmooth(FEdgeSmooth& iBrother) : FEdge(iBrother){
_Normal = iBrother._Normal;
_Face = iBrother._Face;
_FaceMark = iBrother._FaceMark;
_FrsMaterialIndex = iBrother._FrsMaterialIndex;
_isSmooth = true;
}
@@ -913,6 +934,8 @@ public:
}
inline void * face() const {return _Face;}
/*! Returns the face mark of the face it is running across. */
inline bool faceMark() const {return _FaceMark;}
/*! Returns the normal to the Face it is running accross. */
inline const Vec3r& normal() {return _Normal;}
/*! Returns the index of the material of the face it is running accross. */
@@ -921,6 +944,8 @@ public:
const FrsMaterial& frs_material() const ;
inline void setFace(void * iFace) {_Face = iFace;}
/*! Sets the face mark of the face it is running across. */
inline void setFaceMark(bool iFaceMark) {_FaceMark = iFaceMark;}
/*! Sets the normal to the Face it is running accross. */
inline void setNormal(const Vec3r& iNormal) {_Normal = iNormal;}
/*! Sets the index of the material of the face it is running accross. */

View File

@@ -472,6 +472,7 @@ FEdge * ViewEdgeXBuilder::BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer
fe->setId(_currentFId);
fe->setFrsMaterialIndex(ifl.fl->getFace()->frs_materialIndex());
fe->setFace(ifl.fl->getFace());
fe->setFaceMark(ifl.fl->getFace()->GetMark());
fe->setNormal(normal);
fe->setPreviousEdge(feprevious);
if(feprevious)
@@ -585,19 +586,24 @@ FEdge * ViewEdgeXBuilder::BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe)
// get the faces normals and the material indices
Vec3r normalA, normalB;
unsigned matA(0), matB(0);
bool faceMarkA = false, faceMarkB = false;
if(iwe.order){
normalB = (iwe.e->GetbFace()->GetNormal());
matB = (iwe.e->GetbFace()->frs_materialIndex());
faceMarkB = (iwe.e->GetbFace()->GetMark());
if(!(iwe.e->nature() & Nature::BORDER)) {
normalA = (iwe.e->GetaFace()->GetNormal());
matA = (iwe.e->GetaFace()->frs_materialIndex());
faceMarkA = (iwe.e->GetaFace()->GetMark());
}
}else{
normalA = (iwe.e->GetbFace()->GetNormal());
matA = (iwe.e->GetbFace()->frs_materialIndex());
faceMarkA = (iwe.e->GetbFace()->GetMark());
if(!(iwe.e->nature() & Nature::BORDER)) {
normalB = (iwe.e->GetaFace()->GetNormal());
matB = (iwe.e->GetaFace()->frs_materialIndex());
faceMarkB = (iwe.e->GetaFace()->GetMark());
}
}
// Creates the corresponding feature edge
@@ -607,6 +613,8 @@ FEdge * ViewEdgeXBuilder::BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe)
fe->setId(_currentFId);
fe->setaFrsMaterialIndex(matA);
fe->setbFrsMaterialIndex(matB);
fe->setaFaceMark(faceMarkA);
fe->setbFaceMark(faceMarkB);
fe->setNormalA(normalA);
fe->setNormalB(normalB);
fe->setPreviousEdge(feprevious);

View File

@@ -71,6 +71,8 @@ namespace Nature {
static const EdgeNature SUGGESTIVE_CONTOUR = (1 << 5); // 32
/*! true for material boundaries */
static const EdgeNature MATERIAL_BOUNDARY = (1 << 6); // 64
/*! true for user-defined edge marks */
static const EdgeNature EDGE_MARK = (1 << 7); // 128
} // end of namespace Nature

View File

@@ -258,6 +258,7 @@ WFace::WFace(WFace& iBrother)
_VerticesTexCoords = iBrother._VerticesTexCoords;
_Id = iBrother.GetId();
_FrsMaterialIndex = iBrother._FrsMaterialIndex;
_Mark = iBrother._Mark;
userdata = NULL;
iBrother.userdata = new facedata;
((facedata*)(iBrother.userdata))->_copy = this;
@@ -624,12 +625,12 @@ WShape::WShape(WShape& iBrother)
}
}
WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterial)
WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial)
{
// allocate the new face
WFace *face = instanciateFace();
WFace *result = MakeFace(iVertexList, iMaterial, face);
WFace *result = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial, face);
if (0 == result) {
delete face;
return 0;
@@ -637,10 +638,10 @@ WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterial)
return result;
}
WFace * WShape::MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, unsigned iMaterial)
WFace * WShape::MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial)
{
// allocate the new face
WFace *face = MakeFace(iVertexList, iMaterial);
WFace *face = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial);
if(0 == face)
@@ -654,7 +655,7 @@ WFace * WShape::MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsL
return face;
}
WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterial, WFace *face)
WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial, WFace *face)
{
int id = _FaceList.size();
@@ -702,6 +703,10 @@ WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterial, WFace
normal.normalize();
face->setNormal(normal);
vector<bool>::iterator mit = iFaceEdgeMarksList.begin();
face->setMark(*mit);
mit++;
// vertex pointers used to build each edge
vector<WVertex*>::iterator va, vb;
@@ -734,6 +739,9 @@ WFace* WShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterial, WFace
// compute the mean edge value:
_meanEdgeSize += edge->GetaOEdge()->GetVec().norm();
}
edge->setMark(*mit);
mit++;
}
// Add the face to the shape's faces list:

View File

@@ -372,6 +372,7 @@ protected:
WOEdge *_paOEdge; // first oriented edge
WOEdge *_pbOEdge; // second oriented edge
int _nOEdges; // number of oriented edges associated with this edge. (1 means border edge)
bool _Mark; // user-specified edge mark for feature edge detection
int _Id; // Identifier for the edge
public:
@@ -448,6 +449,7 @@ public:
inline WOEdge * GetaOEdge() {return _paOEdge;}
inline WOEdge * GetbOEdge() {return _pbOEdge;}
inline int GetNumberOfOEdges() {return _nOEdges;}
inline bool GetMark() {return _Mark;}
inline int GetId() {return _Id;}
inline WVertex * GetaVertex() {return _paOEdge->GetaVertex();}
inline WVertex * GetbVertex() {return _paOEdge->GetbVertex();}
@@ -480,6 +482,7 @@ public:
}
}
inline void setNumberOfOEdges(int n) {_nOEdges = n;}
inline void setMark(bool mark) {_Mark = mark;}
inline void setId(int id) {_Id = id;}
virtual void ResetUserData() {userdata = 0;}
};
@@ -505,6 +508,7 @@ protected:
int _Id;
unsigned _FrsMaterialIndex;
bool _Mark; // Freestyle face mark (if true, feature edges on this face are ignored)
public:
void *userdata;
@@ -520,6 +524,7 @@ public:
inline Vec3r& GetNormal() {return _Normal;}
inline int GetId() {return _Id;}
inline unsigned frs_materialIndex() const {return _FrsMaterialIndex;}
inline bool GetMark() const {return _Mark;}
const FrsMaterial& frs_material() ;
/*! The vertex of index i corresponds to the a vertex
@@ -663,6 +668,7 @@ public:
inline void setTexCoordsList(const vector<Vec2r>& iTexCoordsList) {_VerticesTexCoords = iTexCoordsList;}
inline void setId(int id) {_Id = id;}
inline void setFrsMaterialIndex(unsigned iMaterialIndex) {_FrsMaterialIndex = iMaterialIndex;}
inline void setMark(bool iMark) {_Mark = iMark;}
/*! designed to build a specialized WEdge
* for use in MakeEdge
@@ -791,7 +797,7 @@ public:
* iMaterialIndex
* The material index for this face
*/
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterialIndex);
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
/*! adds a new face to the shape. The difference with
* the previous method is that this one is designed
@@ -814,7 +820,7 @@ public:
* The list of tex coords, iTexCoordsList[i] corresponding to the
* normal of the vertex iVertexList[i] for that face.
*/
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, unsigned iMaterialIndex);
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
inline void AddEdge(WEdge *iEdge) {_EdgeList.push_back(iEdge);}
inline void AddFace(WFace* iFace) {_FaceList.push_back(iFace);}
@@ -892,7 +898,7 @@ protected:
* face
* The Face that is filled in
*/
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterialIndex, WFace *face);
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex, WFace *face);
};

View File

@@ -258,9 +258,9 @@ void WXFace::ComputeCenter()
/**********************************/
WFace* WXShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterialIndex)
WFace* WXShape::MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex)
{
WFace *face = WShape::MakeFace(iVertexList, iMaterialIndex);
WFace *face = WShape::MakeFace(iVertexList, iFaceEdgeMarksList, iMaterialIndex);
if(0 == face)
return 0;
@@ -277,9 +277,9 @@ WFace* WXShape::MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterialIndex)
return face;
}
WFace * WXShape::MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, unsigned iMaterialIndex)
WFace * WXShape::MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex)
{
WFace *face = WShape::MakeFace(iVertexList, iNormalsList, iTexCoordsList, iMaterialIndex);
WFace *face = WShape::MakeFace(iVertexList, iNormalsList, iTexCoordsList, iFaceEdgeMarksList, iMaterialIndex);
// Vec3r center;
// for(vector<WVertex*>::iterator wv=iVertexList.begin(),wvend=iVertexList.end();

View File

@@ -499,7 +499,7 @@ public:
* determines the face's edges orientation and (so) the
* face orientation.
*/
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, unsigned iMaterialIndex);
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
/*! adds a new face to the shape. The difference with
* the previous method is that this one is designed
@@ -520,7 +520,7 @@ public:
* The list of tex coords, iTexCoordsList[i] corresponding to the
* normal of the vertex iVertexList[i] for that face.
*/
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, unsigned iMaterialIndex);
virtual WFace * MakeFace(vector<WVertex*>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
/*! Reset all edges and vertices flags (which might
* have been set up on a previous pass)

View File

@@ -102,6 +102,8 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs) {
// else if(_current_frs_material)
// shape.setFrsMaterial(*_current_frs_material);
const IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = ifs.faceEdgeMarks();
// sets the current WShape to shape
_current_wshape = &shape;
@@ -128,6 +130,7 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs) {
new_normals,
frs_materials,
texCoords,
faceEdgeMarks,
vindices,
nindices,
mindices,
@@ -139,6 +142,7 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs) {
new_normals,
frs_materials,
texCoords,
faceEdgeMarks,
vindices,
nindices,
mindices,
@@ -150,6 +154,7 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs) {
new_normals,
frs_materials,
texCoords,
faceEdgeMarks,
vindices,
nindices,
mindices,
@@ -163,6 +168,7 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs) {
mindices += numVertexPerFace[index];
if(tindices)
tindices += numVertexPerFace[index];
faceEdgeMarks++;
}
delete[] new_vertices;
@@ -219,6 +225,7 @@ void WingedEdgeBuilder::buildTriangleStrip( const real *vertices,
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,
@@ -232,6 +239,7 @@ void WingedEdgeBuilder::buildTriangleStrip( const real *vertices,
vector<WVertex *> triangleVertices;
vector<Vec3r> triangleNormals;
vector<Vec2r> triangleTexCoords;
vector<bool> triangleFaceEdgeMarks;
while(nDoneVertices < nvertices)
{
@@ -270,10 +278,14 @@ void WingedEdgeBuilder::buildTriangleStrip( const real *vertices,
triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle+1]], texCoords[tindices[nTriangle+1]+1]));
}
}
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle/3] & IndexedFaceSet::FACE_MARK) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle/3] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle/3] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle/3] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
if(mindices)
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, mindices[nTriangle/3]);
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, mindices[nTriangle/3]);
else
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, 0);
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
nDoneVertices++; // with a strip, each triangle is one vertex more
nTriangle++;
}
@@ -283,6 +295,7 @@ void WingedEdgeBuilder::buildTriangleFan( const real *vertices,
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,
@@ -295,6 +308,7 @@ void WingedEdgeBuilder::buildTriangles(const real *vertices,
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,
@@ -304,6 +318,7 @@ void WingedEdgeBuilder::buildTriangles(const real *vertices,
vector<WVertex *> triangleVertices;
vector<Vec3r> triangleNormals;
vector<Vec2r> triangleTexCoords;
vector<bool> triangleFaceEdgeMarks;
// Each triplet of vertices is considered as an independent triangle
for(unsigned i = 0; i < nvertices / 3; i++)
@@ -321,11 +336,16 @@ void WingedEdgeBuilder::buildTriangles(const real *vertices,
triangleTexCoords.push_back(Vec2r(texCoords[tindices[3*i+1]],texCoords[tindices[3*i+1]+1]));
triangleTexCoords.push_back(Vec2r(texCoords[tindices[3*i+2]], texCoords[tindices[3*i+2]+1]));
}
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::FACE_MARK) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
}
if(mindices)
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, mindices[0]);
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, mindices[0]);
else
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords,0);
currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
}

View File

@@ -114,6 +114,7 @@ class LIB_WINGED_EDGE_EXPORT WingedEdgeBuilder : public SceneVisitor
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,
@@ -124,6 +125,7 @@ class LIB_WINGED_EDGE_EXPORT WingedEdgeBuilder : public SceneVisitor
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,
@@ -134,6 +136,7 @@ class LIB_WINGED_EDGE_EXPORT WingedEdgeBuilder : public SceneVisitor
const real *normals,
vector<FrsMaterial>& iMaterials,
const real *texCoords,
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices,
const unsigned *nindices,
const unsigned *mindices,

View File

@@ -51,12 +51,15 @@ struct FreestyleLineStyle;
#define FREESTYLE_LINESET_FE_NOT 4
#define FREESTYLE_LINESET_FE_AND 8
#define FREESTYLE_LINESET_GR_NOT 16
#define FREESTYLE_LINESET_FM_NOT 32
#define FREESTYLE_LINESET_FM_BOTH 64
/* FreestyleLineSet::selection */
#define FREESTYLE_SEL_VISIBILITY 1
#define FREESTYLE_SEL_EDGE_TYPES 2
#define FREESTYLE_SEL_GROUP 4
#define FREESTYLE_SEL_IMAGE_BORDER 8
#define FREESTYLE_SEL_FACE_MARK 16
/* FreestyleLineSet::fedge_types */
#define FREESTYLE_FE_SILHOUETTE 1
@@ -68,6 +71,7 @@ struct FreestyleLineStyle;
#define FREESTYLE_FE_MATERIAL_BOUNDARY 64
#define FREESTYLE_FE_CONTOUR 128
#define FREESTYLE_FE_EXTERNAL_CONTOUR 512
#define FREESTYLE_FE_EDGE_MARK 1024
/* FreestyleLineSet::qi */
#define FREESTYLE_QI_VISIBLE 1

View File

@@ -157,6 +157,9 @@ typedef struct TFace {
#define ME_DRAWEXTRA_FACEAREA (1 << 11)
#define ME_DRAWEXTRA_FACEANG (1 << 12)
#define ME_DRAW_FREESTYLE_EDGE (1 << 13)
#define ME_DRAW_FREESTYLE_FACE (1 << 14)
/* old global flags:
#define G_DRAWEDGES (1 << 18)
#define G_DRAWFACES (1 << 7)

View File

@@ -204,6 +204,7 @@ typedef struct MRecast{
#define ME_LOOSEEDGE (1<<7)
#define ME_SEAM_LAST (1<<8)
#define ME_SHARP (1<<9)
#define ME_FREESTYLE_EDGE (1<<10)
/* puno = vertexnormal (mface) */
/* render assumes flips to be ordered like this */
@@ -225,6 +226,7 @@ typedef struct MRecast{
/* flag (mface) */
#define ME_SMOOTH 1
#define ME_FACE_SEL 2
#define ME_FREESTYLE_FACE 4
/* flag ME_HIDE==16 is used here too */
/* mselect->type */
#define ME_VSEl 0

View File

@@ -1241,6 +1241,7 @@ typedef enum SculptFlags {
#define EDGE_MODE_TAG_SHARP 2
#define EDGE_MODE_TAG_CREASE 3
#define EDGE_MODE_TAG_BEVEL 4
#define EDGE_MODE_TAG_FREESTYLE 5
/* toolsettings->gpencil_flags */
#define GP_TOOL_FLAG_PAINTSESSIONS_ON (1<<0)

View File

@@ -210,6 +210,7 @@ typedef struct ThemeSpace {
char bone_solid[4], bone_pose[4];
char strip[4], strip_select[4];
char cframe[4];
char freestyle_edge_mark[4], freestyle_face_mark[4];
char nurb_uline[4], nurb_vline[4];
char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4];

View File

@@ -1284,6 +1284,11 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "use_freestyle_edge_mark", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FREESTYLE_EDGE);
RNA_def_property_ui_text(prop, "Freestyle Edge Mark", "Edge mark for Freestyle feature edge detection");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE);
RNA_def_property_ui_text(prop, "Loose", "Loose edge");
@@ -1344,6 +1349,11 @@ static void rna_def_mface(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Smooth", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "use_freestyle_face_mark", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FREESTYLE_FACE);
RNA_def_property_ui_text(prop, "Freestyle Face Mark", "Face mark for Freestyle feature edge detection");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1.0f, 1.0f);
@@ -2080,6 +2090,16 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_EDGE);
RNA_def_property_ui_text(prop, "Draw Freestyle Edge Marks", "Display Freestyle edge marks, used with the Freestyle renderer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_freestyle_face_marks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_FACE);
RNA_def_property_ui_text(prop, "Draw Freestyle Face Marks", "Display Freestyle face marks, used with the Freestyle renderer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_extra_edge_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_EDGELEN);
RNA_def_property_ui_text(prop, "Edge Length",

View File

@@ -1168,6 +1168,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""},
{EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""},
{EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""},
{EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""},
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "ToolSettings", NULL);
@@ -1788,6 +1789,16 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
{FREESTYLE_LINESET_GR_NOT, "EXCLUSIVE", 0, "Exclusive", "Select feature edges not belonging to any object in the group."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem face_mark_negation_items[] = {
{0, "INCLUSIVE", 0, "Inclusive", "Select feature edges satisfying the given face mark conditions."},
{FREESTYLE_LINESET_FM_NOT, "EXCLUSIVE", 0, "Exclusive", "Select feature edges not satisfying the given face mark conditions."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem face_mark_condition_items[] = {
{0, "ONE", 0, "One Face", "Select feature edges if one of faces on the right and left has a face mark."},
{FREESTYLE_LINESET_FM_BOTH, "BOTH", 0, "Both Faces", "Select feature edges if both faces on the right and left faces have a face mark."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem freestyle_ui_mode_items[] = {
{FREESTYLE_CONTROL_SCRIPT_MODE, "SCRIPT", 0, "Python Scripting Mode", "Advanced mode for using style modules in Python"},
{FREESTYLE_CONTROL_EDITOR_MODE, "EDITOR", 0, "Parameter Editor Mode", "Basic mode for interactive style parameter editing"},
@@ -1855,6 +1866,11 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection by Image Border", "Select feature edges by image border (less memory consumption).");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "select_by_face_marks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_FACE_MARK);
RNA_def_property_ui_text(prop, "Selection by Face Marks", "Select feature edges by face marks.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "edge_type_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, edge_type_negation_items);
@@ -1877,7 +1893,19 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "group_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, group_negation_items);
RNA_def_property_ui_text(prop, "Edge Type Negation", "Set the negation operation for conditions on feature edge types.");
RNA_def_property_ui_text(prop, "Group Negation", "Set the negation operation for conditions on feature edge types.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "face_mark_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, face_mark_negation_items);
RNA_def_property_ui_text(prop, "Face Mark Negation", "Set the negation operation for the condition on face marks.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "face_mark_condition", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, face_mark_condition_items);
RNA_def_property_ui_text(prop, "Face Mark Condition", "Set a feature edge selection condition on face marks.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "select_silhouette", PROP_BOOLEAN, PROP_NONE);
@@ -1925,6 +1953,11 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "External Contour", "Select external contours.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "select_edge_mark", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EDGE_MARK);
RNA_def_property_ui_text(prop, "Edge Mark", "Select edge marks.");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "visibility", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "qi");
RNA_def_property_enum_items(prop, visibility_items);

View File

@@ -778,6 +778,11 @@ static void rna_def_userdef_theme_spaces_edge(StructRNA *srna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Edge UV Face Select", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop= RNA_def_property(srna, "freestyle_edge_mark", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Freestyle Edge Mark", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
@@ -803,6 +808,11 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
RNA_def_property_range(prop, 1, 10);
RNA_def_property_ui_text(prop, "Face Dot Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop= RNA_def_property(srna, "freestyle_face_mark", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Freestyle Face Mark", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurbs)

View File

@@ -385,6 +385,7 @@ typedef struct VlakRen {
struct Material *mat;
char puno;
char flag, ec;
char freestyle_edge_mark;
int index;
} VlakRen;
@@ -620,6 +621,13 @@ typedef struct LampRen {
#define R_TANGENT 64
#define R_TRACEBLE 128
/* vlakren->freestyle_edge_mark */
#define R_EDGE_V1V2 1
#define R_EDGE_V2V3 2
#define R_EDGE_V3V4 4
#define R_EDGE_V3V1 4
#define R_EDGE_V4V1 8
/* strandbuffer->flag */
#define R_STRAND_BSPLINE 1
#define R_STRAND_B_UNITS 2

View File

@@ -44,6 +44,7 @@
#include "BLI_rand.h"
#include "BLI_memarena.h"
#include "BLI_ghash.h"
#include "BLI_edgehash.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -2735,7 +2736,7 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
v2= mface->v2;
v3= mface->v3;
v4= mface->v4;
flag= mface->flag & ME_SMOOTH;
flag= mface->flag & (ME_SMOOTH | ME_FREESTYLE_FACE);
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
@@ -3235,6 +3236,24 @@ static void add_volume(Render *re, ObjectRen *obr, Material *ma)
BLI_addtail(&re->volumes, vo);
}
static EdgeHash *make_freestyle_edge_mark_hash(MEdge *medge, int totedge)
{
EdgeHash *edge_hash= BLI_edgehash_new();
int a;
for(a=0; a<totedge; a++) {
if(medge[a].flag & ME_FREESTYLE_EDGE)
BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
}
return edge_hash;
}
static int has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
{
MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
return (!medge) ? 0 : 1;
}
static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
@@ -3365,6 +3384,15 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if(!timeoffset) {
EdgeHash *edge_hash;
MEdge *medge;
int totedge;
/* create a hash table of Freestyle edge marks */
medge= dm->getEdgeArray(dm);
totedge= dm->getNumEdges(dm);
edge_hash= make_freestyle_edge_mark_hash(medge, totedge);
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
@@ -3407,12 +3435,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if( mface->mat_nr==a1 ) {
float len;
int edge_mark= 0;
v1= mface->v1;
v2= mface->v2;
v3= mface->v3;
v4= mface->v4;
flag= mface->flag & ME_SMOOTH;
flag= mface->flag & (ME_SMOOTH | ME_FREESTYLE_FACE);
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
@@ -3421,6 +3450,17 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if(v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4);
else vlr->v4= 0;
/* Freestyle edge marks */
if(has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2;
if(has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3;
if (!v4) {
if(has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1;
} else {
if(has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4;
if(has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1;
}
vlr->freestyle_edge_mark= edge_mark;
/* render normals are inverted in render */
if(use_original_normals) {
MFace *mf= me->mface+a;
@@ -3486,6 +3526,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
}
}
/* release the hash table of Freestyle edge marks */
BLI_edgehash_free(edge_hash, NULL);
/* exception... we do edges for wire mode. potential conflict when faces exist... */
end= dm->getNumEdges(dm);
@@ -4271,6 +4314,23 @@ static void check_non_flat_quads(ObjectRen *obr)
/* new normals */
normal_tri_v3( vlr->n,vlr->v3->co, vlr->v2->co, vlr->v1->co);
normal_tri_v3( vlr1->n,vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
/* Freestyle edge marks */
if (vlr->flag & R_DIVIDE_24) {
vlr1->freestyle_edge_mark=
((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
vlr->freestyle_edge_mark=
((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
} else {
vlr1->freestyle_edge_mark=
((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
vlr->freestyle_edge_mark=
((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
}
}
/* clear the flag when not divided */
else vlr->flag &= ~R_DIVIDE_24;