Merged changes in the trunk up to revision 44266 (including BMesh).

Freestyle edge/face marks were ported to BMesh.

Conflicts resolved:
source/blender/editors/mesh/editface.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_meshdata_types.h
source/blender/blenkernel/intern/editderivedmesh.c
This commit is contained in:
Tamito Kajiyama 2012-02-21 01:40:04 +00:00
commit 69289c978e
345 changed files with 57900 additions and 36269 deletions

@ -115,9 +115,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create vertex color attributes */
{
BL::Mesh::vertex_colors_iterator l;
BL::Mesh::tessface_vertex_colors_iterator l;
for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
continue;
@ -147,9 +147,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create uv map attributes */
{
BL::Mesh::uv_textures_iterator l;
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.uv_textures.begin(l); l != b_mesh.uv_textures.end(); ++l) {
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
ustring name = ustring(l->name().c_str());

@ -43,8 +43,8 @@
class VirtualMemoryAllocator
{
public:
virtual UCHAR * allocate( ) = 0 ;
virtual void deallocate( UCHAR * obj ) = 0 ;
virtual void * allocate( ) = 0 ;
virtual void deallocate( void * obj ) = 0 ;
virtual void destroy( ) = 0 ;
virtual void printInfo( ) = 0 ;
@ -161,7 +161,7 @@ public:
/**
* Allocation method
*/
UCHAR * allocate ( )
void * allocate ( )
{
if ( available == 0 )
{
@ -170,13 +170,13 @@ public:
// printf("Allocating %d\n", header[ allocated ]) ;
available -- ;
return stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] ;
return (void*)stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] ;
}
/**
* De-allocation method
*/
void deallocate ( UCHAR * obj )
void deallocate ( void * obj )
{
if ( available == stacksize )
{
@ -184,7 +184,7 @@ public:
}
// printf("De-allocating %d\n", ( obj - data ) / N ) ;
stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] = obj ;
stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] = (UCHAR*)obj ;
available ++ ;
// printf("%d %d\n", allocated, header[ allocated ]) ;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1106,7 +1106,7 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
float dz = (out == index || in == index) ? 1.0f / _dx : gridSize;
int right = _obstacles[index + 1] ? index : index + 1;
int left = _obstacles[index - 1] ? index : index - 1;
float dx = (right == index || right == index) ? 1.0f / _dx : gridSize;
float dx = (right == index || left == index) ? 1.0f / _dx : gridSize;
_xVorticity[vIndex] = (_zVelocity[up] - _zVelocity[down]) * dy + (-_yVelocity[out] + _yVelocity[in]) * dz;
_yVorticity[vIndex] = (_xVelocity[out] - _xVelocity[in]) * dz + (-_zVelocity[right] + _zVelocity[left]) * dx;
@ -1152,7 +1152,7 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
float dz = (out == vIndex || in == vIndex) ? 1.0f / _dx : gridSize;
int right = _obstacles[index + 1] ? vIndex : vIndex + 1;
int left = _obstacles[index - 1] ? vIndex : vIndex - 1;
float dx = (right == vIndex || right == vIndex) ? 1.0f / _dx : gridSize;
float dx = (right == vIndex || left == vIndex) ? 1.0f / _dx : gridSize;
N[0] = (_vorticity[right] - _vorticity[left]) * dx;
N[1] = (_vorticity[up] - _vorticity[down]) * dy;
N[2] = (_vorticity[out] - _vorticity[in]) * dz;

@ -373,7 +373,8 @@ class Mesh(bpy_types.ID):
"""
self.vertices.add(len(vertices))
self.edges.add(len(edges))
self.faces.add(len(faces))
self.loops.add(sum((len(f) for f in faces)))
self.polygons.add(len(faces))
vertices_flat = [f for v in vertices for f in v]
self.vertices.foreach_set("co", vertices_flat)
@ -383,19 +384,15 @@ class Mesh(bpy_types.ID):
self.edges.foreach_set("vertices", edges_flat)
del edges_flat
def treat_face(f):
if len(f) == 3:
if f[2] == 0:
return f[2], f[0], f[1], 0
else:
return f[0], f[1], f[2], 0
elif f[2] == 0 or f[3] == 0:
return f[2], f[3], f[0], f[1]
return f
faces_flat = [v for f in faces for v in treat_face(f)]
self.faces.foreach_set("vertices_raw", faces_flat)
del faces_flat
# this is different in bmesh
loop_index = 0
for i, p in enumerate(self.polygons):
f = faces[i]
loop_len = len(f)
p.loop_start = loop_index
p.loop_total = loop_len
p.vertices = f
loop_index += loop_len
@property
def edge_keys(self):
@ -445,6 +442,20 @@ class MeshFace(StructRNA):
ord_ind(verts[3], verts[0]),
)
class MeshPolygon(StructRNA):
__slots__ = ()
@property
def edge_keys(self):
verts = self.vertices[:]
vlen = len(self.vertices)
return [ord_ind(verts[i], verts[(i+1) % vlen]) for i in range(vlen)]
@property
def loops(self):
start = self.loop_start
end = start + self.loop_total
return range(start, end)
class Text(bpy_types.ID):
__slots__ = ()

@ -24,50 +24,6 @@ from bpy.types import Operator
from bpy.props import EnumProperty
class MeshSelectInteriorFaces(Operator):
'''Select faces where all edges have more than 2 face users'''
bl_idname = "mesh.faces_select_interior"
bl_label = "Select Interior Faces"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
ob = context.active_object
return (ob and ob.type == 'MESH')
def execute(self, context):
from bpy_extras import mesh_utils
ob = context.active_object
context.tool_settings.mesh_select_mode = False, False, True
is_editmode = (ob.mode == 'EDIT')
if is_editmode:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = ob.data
face_list = mesh.faces[:]
face_edge_keys = [face.edge_keys for face in face_list]
edge_face_count = mesh_utils.edge_face_count_dict(mesh)
def test_interior(index):
for key in face_edge_keys[index]:
if edge_face_count[key] < 3:
return False
return True
for index, face in enumerate(face_list):
if(test_interior(index)):
face.select = True
else:
face.select = False
if is_editmode:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
return {'FINISHED'}
class MeshMirrorUV(Operator):
'''Copy mirror UV coordinates on the X axis based on a mirrored mesh'''
bl_idname = "mesh.faces_mirror_uv"

@ -30,6 +30,7 @@ def extend(obj, operator, EXTEND_MODE):
me = obj.data
me_verts = me.vertices
# script will fail without UVs
if not me.uv_textures:
me.uv_textures.new()
@ -52,17 +53,15 @@ def extend(obj, operator, EXTEND_MODE):
'''
def face_edge_vs(vi):
# assume a quad
return [(vi[0], vi[1]), (vi[1], vi[2]), (vi[2], vi[3]), (vi[3], vi[0])]
vlen = len(vi)
return [(vi[i], vi[(i+1) % vlen]) for i in range(vlen)]
vidx_source = face_source.vertices
vidx_target = face_target.vertices
faceUVsource = me.uv_textures.active.data[face_source.index]
uvs_source = [faceUVsource.uv1, faceUVsource.uv2, faceUVsource.uv3, faceUVsource.uv4]
faceUVtarget = me.uv_textures.active.data[face_target.index]
uvs_target = [faceUVtarget.uv1, faceUVtarget.uv2, faceUVtarget.uv3, faceUVtarget.uv4]
uv_layer = me.uv_loop_layers.active.data
uvs_source = [uv_layer[i].uv for i in face_source.loops]
uvs_target = [uv_layer[i].uv for i in face_target.loops]
# vertex index is the key, uv is the value
@ -135,15 +134,12 @@ def extend(obj, operator, EXTEND_MODE):
uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] + (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]])
uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] + (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]])
if not me.uv_textures:
me.uv_textures.new()
face_act = me.faces.active
face_act = me.polygons.active
if face_act == -1:
operator.report({'ERROR'}, "No active face")
return
face_sel = [f for f in me.faces if len(f.vertices) == 4 and f.select]
face_sel = [f for f in me.polygons if len(f.vertices) == 4 and f.select]
face_act_local_index = -1
for i, f in enumerate(face_sel):

@ -88,8 +88,8 @@ class prettyface(object):
self.children = []
else: # blender face
# self.uv = data.uv
self.uv = data.id_data.uv_textures.active.data[data.index].uv # XXX25
uv_layer = data.id_data.uv_loop_layers.active.data
self.uv = [uv_layer[i].uv for i in data.loops]
# cos = [v.co for v in data]
cos = [data.id_data.vertices[v].co for v in data.vertices] # XXX25
@ -158,7 +158,8 @@ class prettyface(object):
I = [i for a, i in angles_co]
#~ fuv = f.uv
fuv = f.id_data.uv_textures.active.data[f.index].uv # XXX25
uv_layer = f.id_data.uv_loop_layers.active.data
fuv = [uv_layer[i].uv for i in f.loops] # XXX25
if self.rot:
fuv[I[2]] = p1
@ -219,15 +220,10 @@ def lightmap_uvpack(meshes,
face_groups = []
for me in meshes:
# Add face UV if it does not exist.
# All new faces are selected.
if not me.uv_textures:
me.uv_textures.new()
if PREF_SEL_ONLY:
faces = [f for f in me.faces if f.select]
faces = [f for f in me.polygons if f.select]
else:
faces = me.faces[:]
faces = me.polygons[:]
if PREF_PACK_IN_ONE:
face_groups[0].extend(faces)
@ -237,6 +233,11 @@ def lightmap_uvpack(meshes,
if PREF_NEW_UVLAYER:
me.uv_textures.new()
# Add face UV if it does not exist.
# All new faces are selected.
if not me.uv_textures:
me.uv_textures.new()
for face_sel in face_groups:
print("\nStarting unwrap")
@ -504,7 +505,7 @@ def lightmap_uvpack(meshes,
for f in face_sel:
# f.image = image
f.id_data.uv_textures.active.data[f.index].image = image # XXX25
f.id_data.uv_loop_layers.active.data[f.index].image = image # XXX25
for me in meshes:
me.update()
@ -528,7 +529,7 @@ def unwrap(operator, context, **kwargs):
if obj and obj.type == 'MESH':
meshes = [obj.data]
else:
meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.faces and me.library is None})
meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.polygons and me.library is None})
if not meshes:
operator.report({'ERROR'}, "No mesh object")

@ -757,12 +757,9 @@ def VectoQuat(vec):
class thickface(object):
__slost__= "v", "uv", "no", "area", "edge_keys"
def __init__(self, face, uvface, mesh_verts):
def __init__(self, face, uv_layer, mesh_verts):
self.v = [mesh_verts[i] for i in face.vertices]
if len(self.v)==4:
self.uv = uvface.uv1, uvface.uv2, uvface.uv3, uvface.uv4
else:
self.uv = uvface.uv1, uvface.uv2, uvface.uv3
self.uv = [uv_layer[i].uv for i in face.loops]
self.no = face.normal
self.area = face.area
@ -892,13 +889,13 @@ def main(context,
if not me.uv_textures: # Mesh has no UV Coords, don't bother.
me.uv_textures.new()
uv_layer = me.uv_textures.active.data
uv_layer = me.uv_loop_layers.active.data
me_verts = list(me.vertices)
if USER_ONLY_SELECTED_FACES:
meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.select]
meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select]
else:
meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces)]
meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]
if not meshFaces:
continue

@ -46,7 +46,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
def NGONINTERP(self, layout, ob, md):
split = layout.split()
split.prop(md, "resolution")
def ARMATURE(self, layout, ob, md):
split = layout.split()
@ -122,6 +126,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
split.prop(md, "width")
split.prop(md, "use_only_vertices")
# -- new modifier only, this may be reverted in favor of 2.62 mod.
split = layout.split()
split.prop(md, "use_even_offset")
split.prop(md, "use_distance_offset")
# -- end
layout.label(text="Limit Method:")
layout.row().prop(md, "limit_method", expand=True)
if md.limit_method == 'ANGLE':

@ -522,16 +522,15 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.operator("mesh.select_nth", text="Every N Number of Verts")
layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
layout.operator("mesh.faces_select_interior", text="Interior Faces")
layout.operator("mesh.select_interior_faces", text="Interior Faces")
layout.operator("mesh.select_axis", text="Side of Active")
layout.separator()
layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES'
layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS'
layout.operator("mesh.select_by_number_vertices", text = "By Number of Verts")
if context.scene.tool_settings.mesh_select_mode[2] == False:
layout.operator("mesh.select_non_manifold", text="Non Manifold")
layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER'
layout.operator("mesh.select_loose_verts", text = "Loose Verts/Edges")
layout.operator("mesh.select_similar", text="Similar")
layout.separator()
@ -1502,6 +1501,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Region")
layout.operator("view3d.edit_mesh_extrude_individual_move", text="Extrude Individual")
layout.operator("mesh.dissolve_limited")
layout.operator("mesh.duplicate_move")
layout.operator("mesh.delete", text="Delete...")
@ -1532,15 +1532,18 @@ class VIEW3D_MT_edit_mesh_specials(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mesh.subdivide", text="Subdivide").smoothness = 0.0
"""
layout.operator("mesh.subdivide", text="Subdivide Smooth").smoothness = 1.0
"""
layout.operator("mesh.merge", text="Merge...")
layout.operator("mesh.remove_doubles")
layout.operator("mesh.dissolve_limited")
layout.operator("mesh.hide", text="Hide")
layout.operator("mesh.reveal", text="Reveal")
layout.operator("mesh.select_all").action = 'INVERT'
layout.operator("mesh.flip_normals")
layout.operator("mesh.vertices_smooth", text="Smooth")
# layout.operator("mesh.bevel", text="Bevel")
layout.operator("mesh.bevel", text="Bevel")
layout.operator("mesh.faces_shade_smooth")
layout.operator("mesh.faces_shade_flat")
layout.operator("mesh.blend_from_shape")
@ -1614,6 +1617,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("mesh.rip_move")
layout.operator("mesh.split")
layout.operator("mesh.separate")
layout.operator("mesh.vert_connect")
layout.separator()
@ -1657,7 +1661,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
layout.operator("mesh.mark_freestyle_edge")
layout.operator("mesh.mark_freestyle_edge").clear = False
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
layout.separator()
@ -1667,6 +1671,10 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
layout.operator("mesh.bridge_edge_loops", text="Bridge Two Edge Loops")
layout.separator()
layout.operator("TRANSFORM_OT_edge_slide")
layout.operator("TRANSFORM_OT_edge_crease")
layout.operator("mesh.loop_multi_select", text="Edge Loop").ring = False
@ -1699,12 +1707,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
layout.operator("mesh.fgon_make")
layout.operator("mesh.fgon_clear")
layout.separator()
layout.operator("mesh.mark_freestyle_face")
layout.operator("mesh.mark_freestyle_face").clear = False
layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
layout.separator()
@ -1728,9 +1731,9 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
layout.operator_menu_enum("mesh.uvs_rotate", "direction")
layout.operator_menu_enum("mesh.uvs_mirror", "axis")
layout.operator("mesh.uvs_reverse")
layout.operator_menu_enum("mesh.colors_rotate", "direction")
layout.operator_menu_enum("mesh.colors_mirror", "axis")
layout.operator("mesh.colors_reverse")
class VIEW3D_MT_edit_mesh_normals(Menu):

@ -93,6 +93,7 @@ add_subdirectory(editors)
add_subdirectory(windowmanager)
add_subdirectory(blenkernel)
add_subdirectory(blenlib)
add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)

@ -3,6 +3,7 @@ Import ('env')
import sys
SConscript(['avi/SConscript',
'bmesh/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',

@ -28,21 +28,49 @@
#ifndef __BKE_DERIVEDMESH_H__
#define __BKE_DERIVEDMESH_H__
/** \file BKE_DerivedMesh.h
* \ingroup bke
*
* \todo
* - Make drawMapped* functions take a predicate function that
* determines whether to draw the edge (this predicate can
* also set color, etc). This will be slightly more general
* and allow some of the functions to be collapsed.
* - Once accessor functions are added then single element draw
* functions can be implemented using primitive accessors.
* - Add function to dispatch to renderer instead of using
* conversion to DLM.
/*
Basic design of the DerivedMesh system:
DerivedMesh is a common set of interfaces for mesh systems.
There are three main mesh data structures in Blender: Mesh, CDDM, and BMesh.
These, and a few others, all implement DerivedMesh interfaces,
which contains unified drawing interfaces, a few utility interfaces,
and a bunch of read-only interfaces intended mostly for conversion from
one format to another.
All Mesh structures in blender make use of CustomData, which is used to store
per-element attributes and interpolate them (e.g. uvs, vcols, vgroups, etc).
Mesh is the "serialized" structure, used for storing object-mode mesh data
and also for saving stuff to disk. It's interfaces are also what DerivedMesh
uses to communicate with.
CDDM is a little mesh library, that uses Mesh data structures in the backend.
It's mostly used for modifiers, and has the advantages of not taking much
resources.
BMesh is a full-on brep, used for editmode, some modifiers, etc. It's much
more capable (if memory-intensive) then CDDM.
DerivedMesh is somewhat hackish. Many places assumes that a DerivedMesh is
a CDDM (most of the time by simply copying it and converting it to one).
CDDM is the original structure for modifiers, but has since been superseded
by BMesh, at least for the foreseeable future.
*/
/*
* Note: This sturcture is read-only, for all practical purposes.
* At some point in the future, we may want to consider
* creating a replacement structure that implements a proper
* abstract mesh kernel interface. Or, we can leave this
* as it is and stick with using BMesh and CDDM.
*/
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "BKE_bvhutils.h"
@ -53,20 +81,26 @@ struct MTFace;
struct Object;
struct Scene;
struct Mesh;
struct EditMesh;
struct BMEditMesh;
struct KeyBlock;
struct ModifierData;
struct MCol;
struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
struct BMEditMesh;
struct ListBase;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
#define SUB_ELEMS_VERT 0
#define SUB_ELEMS_EDGE 2
#define SUB_ELEMS_FACE 4
#define SUB_ELEMS_FACE 50
/*
Note: all mface interfaces now officially operate on tesselated data.
Also, the mface origindex layer indexes mpolys, not mfaces.
*/
typedef struct DMGridData {
float co[3];
@ -80,15 +114,15 @@ typedef struct DMGridAdjacency {
typedef enum DerivedMeshType {
DM_TYPE_CDDM,
DM_TYPE_EDITMESH,
DM_TYPE_EDITBMESH,
DM_TYPE_CCGDM
} DerivedMeshType;
typedef struct DerivedMesh DerivedMesh;
struct DerivedMesh {
/* Private DerivedMesh data, only for internal DerivedMesh use */
CustomData vertData, edgeData, faceData;
int numVertData, numEdgeData, numFaceData;
CustomData vertData, edgeData, faceData, loopData, polyData;
int numVertData, numEdgeData, numTessFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache bvhCache;
@ -96,23 +130,29 @@ struct DerivedMesh {
DerivedMeshType type;
float auto_bump_scale;
/* calculate vert and face normals */
void (*calcNormals)(DerivedMesh *dm);
/* recalculates mesh tesselation */
void (*recalcTesselation)(DerivedMesh *dm);
/* Misc. Queries */
/* Also called in Editmode */
int (*getNumVerts)(DerivedMesh *dm);
/* Also called in Editmode */
int (*getNumFaces)(DerivedMesh *dm);
int (*getNumEdges)(DerivedMesh *dm);
int (*getNumTessFaces)(DerivedMesh *dm);
int (*getNumLoops)(DerivedMesh *dm);
int (*getNumPolys)(DerivedMesh *dm);
/* copy a single vert/edge/face from the derived mesh into
/* copy a single vert/edge/tesselated face from the derived mesh into
* *{vert/edge/face}_r. note that the current implementation
* of this function can be quite slow, iterating over all
* elements (editmesh)
*/
void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);
void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *face_r);
/* return a pointer to the entire array of verts/edges/face from the
* derived mesh. if such an array does not exist yet, it will be created,
@ -121,21 +161,27 @@ struct DerivedMesh {
*/
struct MVert *(*getVertArray)(DerivedMesh *dm);
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
struct MFace *(*getFaceArray)(DerivedMesh *dm);
struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
struct MLoop *(*getLoopArray)(DerivedMesh *dm);
struct MPoly *(*getPolyArray)(DerivedMesh *dm);
/* copy all verts/edges/faces from the derived mesh into
* *{vert/edge/face}_r (must point to a buffer large enough)
*/
void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r);
void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r);
void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *face_r);
void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *loop_r);
void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *poly_r);
/* return a copy of all verts/edges/faces from the derived mesh
* it is the caller's responsibility to free the returned pointer
*/
struct MVert *(*dupVertArray)(DerivedMesh *dm);
struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
struct MFace *(*dupFaceArray)(DerivedMesh *dm);
struct MFace *(*dupTessFaceArray)(DerivedMesh *dm);
struct MLoop *(*dupLoopArray)(DerivedMesh *dm);
struct MPoly *(*dupPolyArray)(DerivedMesh *dm);
/* return a pointer to a single element of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
@ -143,7 +189,7 @@ struct DerivedMesh {
*/
void *(*getVertData)(DerivedMesh *dm, int index, int type);
void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
void *(*getFaceData)(DerivedMesh *dm, int index, int type);
void *(*getTessFaceData)(DerivedMesh *dm, int index, int type);
/* return a pointer to the entire array of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
@ -151,8 +197,21 @@ struct DerivedMesh {
*/
void *(*getVertDataArray)(DerivedMesh *dm, int type);
void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
void *(*getFaceDataArray)(DerivedMesh *dm, int type);
void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
/*retrieves the base CustomData structures for
verts/edges/tessfaces/loops/facdes*/
CustomData *(*getVertDataLayout)(DerivedMesh *dm);
CustomData *(*getEdgeDataLayout)(DerivedMesh *dm);
CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm);
CustomData *(*getLoopDataLayout)(DerivedMesh *dm);
CustomData *(*getPolyDataLayout)(DerivedMesh *dm);
/*copies all customdata for an element source into dst at index dest*/
void (*copyFromVertCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
void (*copyFromEdgeCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
void (*copyFromFaceCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
/* optional grid access for subsurf */
int (*getNumGrids)(DerivedMesh *dm);
int (*getGridSize)(DerivedMesh *dm);
@ -208,6 +267,10 @@ struct DerivedMesh {
/* Get smooth vertex normal, undefined if index is not valid */
void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
/* Get a map of vertices to faces
*/
struct ListBase *(*getPolyMap)(struct Object *ob, DerivedMesh *dm);
/* Get a map of vertices to faces
*/
struct ListBase *(*getFaceMap)(struct Object *ob, DerivedMesh *dm);
@ -255,8 +318,8 @@ struct DerivedMesh {
* o Drawing options too complicated to enumerate, look at code.
*/
void (*drawFacesTex)(DerivedMesh *dm,
int (*setDrawOptions)(struct MTFace *tface,
int has_mcol, int matnr),
int (*setDrawOptions)(struct MTFace *tface,
int has_vcol, int matnr),
int (*compareDrawOptions)(void *userData,
int cur_index,
int next_index),
@ -357,15 +420,16 @@ void DM_init_funcs(DerivedMesh *dm);
* of vertices, edges and faces (doesn't allocate memory for them, just
* sets up the custom data layers)
*/
void DM_init(DerivedMesh *dm, DerivedMeshType type,
int numVerts, int numEdges, int numFaces);
void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
int numFaces, int numLoops, int numPolys);
/* utility function to initialise a DerivedMesh for the desired number
* of vertices, edges and faces, with a layer setup copied from source
*/
void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
DerivedMeshType type,
int numVerts, int numEdges, int numFaces);
DerivedMeshType type,
int numVerts, int numEdges, int numFaces,
int numLoops, int numPolys);
/* utility function to release a DerivedMesh's layers
* returns 1 if DerivedMesh has to be released by the backend, 0 otherwise
@ -374,7 +438,15 @@ int DM_release(DerivedMesh *dm);
/* utility function to convert a DerivedMesh to a Mesh
*/
void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob);
struct BMEditMesh *DM_to_editbmesh(struct Object *ob, struct DerivedMesh *dm,
struct BMEditMesh *existing, int do_tesselate);
/* conversion to bmesh only */
void DM_to_bmesh_ex(struct DerivedMesh *dm, struct BMesh *bm);
struct BMesh *DM_to_bmesh(struct Object *ob, struct DerivedMesh *dm);
/* utility function to convert a DerivedMesh to a shape key block
*/
@ -392,11 +464,15 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
* freed, see BKE_customdata.h for the different options
*/
void DM_add_vert_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
void *layer);
void DM_add_tessface_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype,
void *layer);
void DM_add_poly_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
/* custom data access functions
* return pointer to data from first layer which matches type
@ -405,7 +481,7 @@ void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
*/
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
/* custom data layer access functions
* return pointer to first data layer which matches type (a flat array)
@ -414,7 +490,9 @@ void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
*/
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
/* custom data setting functions
* copy supplied data into first layer of type using layer's copy function
@ -422,7 +500,7 @@ void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
*/
void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_tessface_data(struct DerivedMesh *dm, int index, int type, void *data);
/* custom data copy functions
* copy count elements from source_index in source to dest_index in dest
@ -432,7 +510,11 @@ void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
void DM_copy_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_poly_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
/* custom data free functions
@ -441,7 +523,14 @@ void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
*/
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count);
void DM_free_loop_data(struct DerivedMesh *dm, int index, int count);
void DM_free_poly_data(struct DerivedMesh *dm, int index, int count);
/*sets up mpolys for a DM based on face iterators in source*/
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_tessface(DerivedMesh *dm);
/* interpolates vertex data from the vertices indexed by src_indices in the
* source mesh using the given weights and stores the result in the vertex
@ -472,12 +561,20 @@ void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
* vert_weights[i] multiplied by weights[i].
*/
typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
void DM_interp_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
float *weights, FaceVertWeight *vert_weights,
int count, int dest_index);
void DM_swap_face_data(struct DerivedMesh *dm, int index, const int *corner_indices);
void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices);
void DM_interp_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
float *weights, int count, int dest_index);
void DM_interp_poly_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
float *weights, int count, int dest_index);
/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
void vDM_ColorBand_store(struct ColorBand *coba);
@ -493,11 +590,15 @@ DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob,
DerivedMesh *mesh_get_derived_deform(struct Scene *scene, struct Object *ob,
CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob, struct ModifierData *md);
DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob,
struct ModifierData *md, int build_shapekey_layers);
DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob,
CustomDataMask dataMask);
DerivedMesh *getEditDerivedBMesh(struct BMEditMesh *em, struct Object *ob,
float (*vertexCos)[3]);
DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index);
/* same as above but wont use render settings */
@ -516,20 +617,21 @@ DerivedMesh *mesh_create_derived_no_virtual(struct Scene *scene, struct Object *
DerivedMesh *mesh_create_derived_physics(struct Scene *scene, struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
DerivedMesh *editmesh_get_derived(struct EditMesh *em, float (*vertexCos)[3]);
DerivedMesh *editmesh_get_derived_base(struct Object *, struct EditMesh *em);
DerivedMesh *editmesh_get_derived_cage(struct Scene *scene, struct Object *,
struct EditMesh *em, CustomDataMask dataMask);
DerivedMesh *editmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *,
struct EditMesh *em, DerivedMesh **final_r,
DerivedMesh *editbmesh_get_derived(struct BMEditMesh *em, float (*vertexCos)[3]);
DerivedMesh *editbmesh_get_derived_base(struct Object *, struct BMEditMesh *em);
DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask);
DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *,
struct BMEditMesh *em, DerivedMesh **final_r,
CustomDataMask dataMask);
float (*editmesh_get_vertex_cos(struct EditMesh *em, int *numVerts_r))[3];
int editmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask);
float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *numVerts_r))[3];
int editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
CustomDataMask dataMask, int build_shapekey_layers);
/* returns an array of deform matrices for crazyspace correction, and the
number of modifiers left */
int editmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct EditMesh *em,
int editbmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct BMEditMesh *em,
float (**deformmats)[3][3], float (**deformcos)[3]);
/* returns an array of deform matrices for crazyspace correction when sculpting,
@ -574,16 +676,6 @@ typedef struct DMVertexAttribs {
int tottface, totmcol, tottang, totorco;
} DMVertexAttribs;
/* should be local, bmesh replaces this */
typedef struct {
DerivedMesh dm;
struct EditMesh *em;
float (*vertexCos)[3];
float (*vertexNos)[3];
float (*faceNos)[3];
} EditMeshDerivedMesh;
void DM_vertex_attributes_from_gpu(DerivedMesh *dm,
struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
@ -593,6 +685,8 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm);
/* Set object's bounding box based on DerivedMesh min/max data */
void DM_set_object_boundbox(struct Object *ob, DerivedMesh *dm);
void DM_init_origspace(DerivedMesh *dm);
/* debug only */
#ifndef NDEBUG
char *DM_debug_info(DerivedMesh *dm);

@ -107,6 +107,7 @@ void armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outma
void armature_loc_world_to_pose(struct Object *ob, float *inloc, float *outloc);
void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc);
void armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]);
void armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);

@ -90,6 +90,7 @@ extern void BKE_reset_undo(void);
extern char *BKE_undo_menu_string(void);
extern void BKE_undo_number(struct bContext *C, int nr);
extern const char *BKE_undo_get_name(int nr, int *active);
void BKE_undo_save(char *fname);
extern void BKE_undo_save_quit(void);
extern struct Main *BKE_undo_get_main(struct Scene **scene);

@ -44,6 +44,7 @@
#include "BLI_editVert.h"
#include "BKE_DerivedMesh.h"
//XXX #include "transform.h"
#include "bmesh.h"
/*forward declerations*/
struct BME_Vert;
@ -51,6 +52,7 @@ struct BME_Edge;
struct BME_Poly;
struct BME_Loop;
/*NOTE: this is the bmesh 1.0 code. it's completely outdated.*/
/*Notes on further structure Cleanup:
-Remove the tflags, they belong in custom data layers
@ -208,9 +210,13 @@ int BME_loop_reverse(struct BME_Mesh *bm, struct BME_Poly *f);
#define BME_BEVEL_RUNNING (1<<9)
#define BME_BEVEL_RES (1<<10)
#define BME_BEVEL_EVEN (1<<11) /* this is a new setting not related to old (trunk bmesh bevel code) but adding
* here because they are mixed - campbell */
#define BME_BEVEL_DIST (1<<12) /* same as above */
typedef struct BME_TransData {
BME_Mesh *bm; /* the bmesh the vert belongs to */
BME_Vert *v; /* pointer to the vert this tdata applies to */
BMesh *bm; /* the bmesh the vert belongs to */
BMVert *v; /* pointer to the vert this tdata applies to */
float co[3]; /* the original coordinate */
float org[3]; /* the origin */
float vec[3]; /* a directional vector; always, always normalize! */
@ -231,7 +237,7 @@ typedef struct BME_TransData_Head {
} BME_TransData_Head;
typedef struct BME_Glob { /* stored in Global G for Transform() purposes */
BME_Mesh *bm;
BMesh *bm;
BME_TransData_Head *td;
struct TransInfo *Trans; /* a pointer to the global Trans struct */
int imval[2]; /* for restoring original mouse co when initTransform() is called multiple times */
@ -239,10 +245,10 @@ typedef struct BME_Glob { /* stored in Global G for Transform() purposes */
int res;
} BME_Glob;
struct BME_TransData *BME_get_transdata(struct BME_TransData_Head *td, struct BME_Vert *v);
struct BME_TransData *BME_get_transdata(struct BME_TransData_Head *td, struct BMVert *v);
void BME_free_transdata(struct BME_TransData_Head *td);
float *BME_bevel_calc_polynormal(struct BME_Poly *f, struct BME_TransData_Head *td);
struct BME_Mesh *BME_bevel(struct BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd);
struct BMesh *BME_bevel(struct BMEditMesh *em, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd);
/*CONVERSION FUNCTIONS*/
struct BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em);

@ -38,12 +38,17 @@
#include "BKE_DerivedMesh.h"
struct DerivedMesh;
struct BMEditMesh;
struct EditMesh;
struct Mesh;
struct Object;
/* creates a new CDDerivedMesh */
struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces,
int numLoops, int numPolys);
/*tests if a given DerivedMesh is a CDDM*/
int CDDM_Check(struct DerivedMesh *dm);
/* creates a CDDerivedMesh from the given Mesh, this will reference the
original data in Mesh, but it is safe to apply vertex coordinates or
@ -51,8 +56,11 @@ struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
data to not overwrite the original */
struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh, struct Object *ob);
/* creates a CDDerivedMesh from the given EditMesh */
struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me);
/* creates a CDDerivedMesh from the given BMEditMesh */
DerivedMesh *CDDM_from_BMEditMesh(struct BMEditMesh *em, struct Mesh *me, int use_mdisps, int use_tessface);
/* merge verts */
DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap);
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
@ -65,13 +73,20 @@ DerivedMesh *CDDM_from_curve_customDB(struct Object *ob, struct ListBase *dispba
* custom element data.
*/
struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
/* creates a CDDerivedMesh with the same layer stack configuration as the
* given DerivedMesh and containing the requested numbers of elements.
* elements are initialised to all zeros
*/
struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
int numVerts, int numEdges, int numFaces);
int numVerts, int numEdges, int numFaces,
int numLoops, int numPolys);
/*converts mfaces to mpolys. note things may break if there are not valid
*medges surrounding each mface.
*/
void CDDM_tessfaces_to_faces(struct DerivedMesh *dm);
/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert
* layer is a referenced layer, it will be duplicate to not overwrite the
@ -82,19 +97,31 @@ void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]);
/* recalculates vertex and face normals for a CDDerivedMesh
*/
void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
void CDDM_calc_normals_tessface(struct DerivedMesh *dm);
/* calculates edges for a CDDerivedMesh (from face data)
* this completely replaces the current edge data in the DerivedMesh
* builds edges from the tesselated face data.
*/
void CDDM_calc_edges_tessface(struct DerivedMesh *dm);
/* same as CDDM_calc_edges_tessface only makes edges from ngon faces instead of tesselation
faces*/
void CDDM_calc_edges(struct DerivedMesh *dm);
/* reconstitute face triangulation */
void CDDM_recalc_tesselation(struct DerivedMesh *dm);
void CDDM_recalc_tesselation_ex(struct DerivedMesh *dm, const int do_face_nor_cpy);
/* lowers the number of vertices/edges/faces in a CDDerivedMesh
* the layer data stays the same size
*/
void CDDM_lower_num_verts(struct DerivedMesh *dm, int numVerts);
void CDDM_lower_num_edges(struct DerivedMesh *dm, int numEdges);
void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
void CDDM_lower_num_polys(struct DerivedMesh *dm, int numPolys);
void CDDM_lower_num_tessfaces(DerivedMesh *dm, int numTessFaces);
/* vertex/edge/face access functions
* should always succeed if index is within bounds
@ -102,7 +129,9 @@ void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
*/
struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index);
struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index);
struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
struct MFace *CDDM_get_tessface(struct DerivedMesh *dm, int index);
struct MLoop *CDDM_get_loop(struct DerivedMesh *dm, int index);
struct MPoly *CDDM_get_poly(struct DerivedMesh *dm, int index);
/* vertex/edge/face array access functions - return the array holding the
* desired data
@ -111,6 +140,18 @@ struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
*/
struct MVert *CDDM_get_verts(struct DerivedMesh *dm);
struct MEdge *CDDM_get_edges(struct DerivedMesh *dm);
struct MFace *CDDM_get_faces(struct DerivedMesh *dm);
struct MFace *CDDM_get_tessfaces(struct DerivedMesh *dm);
struct MLoop *CDDM_get_loops(struct DerivedMesh *dm);
struct MPoly *CDDM_get_polys(struct DerivedMesh *dm);
/*Assigns news m*** layers to the cddm. Note that you must handle
freeing the old ones yourself. Also you must ensure dm->num****Data
is correct.*/
void CDDM_set_mvert(struct DerivedMesh *dm, struct MVert *mvert);
void CDDM_set_medge(struct DerivedMesh *dm, struct MEdge *medge);
void CDDM_set_mface(struct DerivedMesh *dm, struct MFace *mface);
void CDDM_set_mloop(struct DerivedMesh *dm, struct MLoop *mloop);
void CDDM_set_mpoly(struct DerivedMesh *dm, struct MPoly *mpoly);
#endif

@ -40,11 +40,15 @@ extern "C" {
#include "../blenloader/BLO_sys_types.h" /* XXX, should have a more generic include for this */
struct BMesh;
struct ID;
struct CustomData;
struct CustomDataLayer;
typedef uint64_t CustomDataMask;
/*a data type large enough to hold 1 element from any customdata layer type*/
typedef struct {unsigned char data[64];} CDBlockBytes;
extern const CustomDataMask CD_MASK_BAREMESH;
extern const CustomDataMask CD_MASK_MESH;
extern const CustomDataMask CD_MASK_EDITMESH;
@ -69,6 +73,25 @@ extern const CustomDataMask CD_MASK_FACECORNERS;
#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
/* Checks if the layer at physical offset layern (in data->layers) support math
* the below operations.
*/
int CustomData_layer_has_math(struct CustomData *data, int layern);
/*copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
another, while not overwriting anything else (e.g. flags). probably only
implemented for mloopuv/mloopcol, for now.*/
void CustomData_data_copy_value(int type, void *source, void *dest);
/* compares if data1 is equal to data2. type is a valid CustomData type
* enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
* the data, if it exists, otherwise memcmp is used.*/
int CustomData_data_equals(int type, void *data1, void *data2);
void CustomData_data_initminmax(int type, void *min, void *max);
void CustomData_data_dominmax(int type, void *data, void *min, void *max);
void CustomData_data_multiply(int type, void *data, float fac);
void CustomData_data_add(int type, void *data1, void *data2);
/* initialises a CustomData object with the same layer setup as source.
* mask is a bitfield where (mask & (1 << (layer type))) indicates
* if a layer should be copied or not. alloctype must be one of the above. */
@ -83,6 +106,12 @@ void CustomData_update_typemap(struct CustomData *data);
void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
CustomDataMask mask, int alloctype, int totelem);
/*bmesh version of CustomData_merge; merges the layouts of source and dest,
then goes through the mesh and makes sure all the customdata blocks are
consistent with the new layout.*/
void CustomData_bmesh_merge(struct CustomData *source, struct CustomData *dest,
int mask, int alloctype, struct BMesh *bm, int type);
/* frees data associated with a CustomData object (doesn't free the object
* itself, though)
*/
@ -308,8 +337,9 @@ int CustomData_verify_versions(struct CustomData *data, int index);
/*BMesh specific customdata stuff*/
void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
struct CustomData *ldata);
struct CustomData *ldata, int totloop, int totpoly);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
/* External file storage */

@ -48,8 +48,10 @@ extern "C" {
#endif
void free_key(struct Key *sc);
void free_key_nolib(struct Key *key);
struct Key *add_key(struct ID *id);
struct Key *copy_key(struct Key *key);
struct Key *copy_key_nolib(struct Key *key);
void make_local_key(struct Key *key);
void sort_keys(struct Key *key);

@ -36,7 +36,8 @@
struct BoundBox;
struct DispList;
struct ListBase;
struct EditMesh;
struct BMEditMesh;
struct BMesh;
struct Mesh;
struct MPoly;
struct MLoop;
@ -60,19 +61,50 @@ struct UvElement;
extern "C" {
#endif
struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
/*
* this function recreates a tesselation.
* returns number of tesselation faces.
*
* use_poly_origindex sets whether or not the tesselation faces' origindex
* layer should point to original poly indices or real poly indices.
*
* use_face_origindex sets the tesselation faces' origindex layer
* to point to the tesselation faces themselves, not the polys.
*
* if both of the above are 0, it'll use the indices of the mpolys of the MPoly
* data in pdata, and ignore the origindex layer altogether.
*/
int mesh_recalcTesselation(struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
struct MVert *mvert,
int totface, int totloop, int totpoly,
const int do_face_normals);
/* for forwards compat only quad->tri polys to mface, skip ngons.
*/
int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int totloop, int totpoly);
/*calculates a face normal.*/
void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart,
struct MVert *mvarray, float no[3]);
void mesh_calc_poly_normal_coords(struct MPoly *mpoly, struct MLoop *loopstart,
const float (*vertex_coords)[3], float no[3]);
void mesh_calc_poly_center(struct MPoly *mpoly, struct MLoop *loopstart,
struct MVert *mvarray, float cent[3]);
float mesh_calc_poly_area(struct MPoly *mpoly, struct MLoop *loopstart,
struct MVert *mvarray, float polynormal[3]);
void unlink_mesh(struct Mesh *me);
void free_mesh(struct Mesh *me);
void free_mesh(struct Mesh *me, int unlink);
struct Mesh *add_mesh(const char *name);
struct Mesh *copy_mesh(struct Mesh *me);
void mesh_update_customdata_pointers(struct Mesh *me);
void mesh_update_customdata_pointers(struct Mesh *me, const short do_ensure_tess_cd);
void make_local_mesh(struct Mesh *me);
void boundbox_mesh(struct Mesh *me, float *loc, float *size);
void tex_space_mesh(struct Mesh *me);
@ -82,17 +114,26 @@ int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex,
struct Mesh *get_mesh(struct Object *ob);
void set_mesh(struct Object *ob, struct Mesh *me);
void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *_totvert,
struct MEdge **alledge, int *_totedge, struct MFace **allface, int *_totface);
int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase,
struct MVert **allvert, int *_totvert, struct MEdge **alledge, int *_totedge,
struct MFace **allface, int *_totface);
int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *totvert,
struct MEdge **alledge, int *totedge, struct MLoop **allloop, struct MPoly **allpoly,
int *totloop, int *totpoly);
int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase, struct MVert **allvert, int *_totvert,
struct MEdge **alledge, int *_totedge, struct MLoop **allloop, struct MPoly **allpoly,
int *_totloop, int *_totpoly);
void nurbs_to_mesh(struct Object *ob);
void mesh_to_curve(struct Scene *scene, struct Object *ob);
void free_dverts(struct MDeformVert *dvert, int totvert);
void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
void mesh_delete_material_index(struct Mesh *me, short index);
void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
void convert_mfaces_to_mpolys(struct Mesh *mesh);
void mesh_calc_normals_tessface(struct MVert *mverts, int numVerts,struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
/*used for unit testing; compares two meshes, checking only
differences we care about. should be usable with leaf's
testing framework I get RNA work done, will use hackish
testing code for now.*/
const char *mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *mesh_get_bb(struct Object *ob);
void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
@ -106,7 +147,21 @@ void mesh_strip_loose_edges(struct Mesh *me);
/* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
* and vertex normals are stored in actual mverts.
*/
void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
void mesh_calc_normals_mapping(
struct MVert *mverts, int numVerts,
struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]);
/* extended version of 'mesh_calc_normals' with option not to calc vertex normals */
void mesh_calc_normals_mapping_ex(
struct MVert *mverts, int numVerts,
struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3],
const short only_face_normals);
void mesh_calc_normals(
struct MVert *mverts, int numVerts,
struct MLoop *mloop, struct MPoly *mpolys,
int numLoops, int numPolys, float (*polyNors_r)[3]);
/* Return a newly MEM_malloc'd array of all the mesh vertex locations
* (_numVerts_r_ may be NULL) */
@ -129,6 +184,29 @@ typedef struct UvMapVert {
unsigned char tfindex, separate, flag;
} UvMapVert;
/* UvElement stores per uv information so that we can quickly access information for a uv.
* it is actually an improved UvMapVert, including an island and a direct pointer to the face
* to avoid initialising face arrays */
typedef struct UvElement {
/* Next UvElement corresponding to same vertex */
struct UvElement *next;
/* Face the element belongs to */
struct BMFace *face;
/* Index in the editFace of the uv */
unsigned char tfindex;
/* Whether this element is the first of coincident elements */
unsigned char separate;
/* general use flag */
unsigned char flag;
/* If generating element map with island sorting, this stores the island index */
unsigned short island;
} UvElement;
/* UvElementMap is a container for UvElements of a mesh. It stores some UvElements belonging to the
* same uv island in sequence and the number of uvs per island so it is possible to access all uvs
* belonging to an island directly by iterating through the buffer.
*/
typedef struct UvElementMap {
/* address UvElements by their vertex */
struct UvElement **vert;
@ -142,27 +220,11 @@ typedef struct UvElementMap {
int *islandIndices;
} UvElementMap;
typedef struct UvElement {
/* Next UvElement corresponding to same vertex */
struct UvElement *next;
/* Face the element belongs to */
struct EditFace *face;
/* Index in the editFace of the uv */
unsigned char tfindex;
/* Whether this element is the first of coincident elements */
unsigned char separate;
/* general use flag */
unsigned char flag;
/* If generating element map with island sorting, this stores the island index */
unsigned short island;
} UvElement;
/* invalid island index is max short. If any one has the patience
* to make that many islands, he can bite me :p */
#define INVALID_ISLAND 0xFFFF
UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit);
UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit);
UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
void free_uv_vert_map(UvVertMap *vmap);
@ -171,6 +233,9 @@ typedef struct IndexNode {
struct IndexNode *next, *prev;
int index;
} IndexNode;
void create_vert_poly_map(struct ListBase **map, IndexNode **mem,
struct MPoly *mface, struct MLoop *mloop,
const int totvert, const int totface, const int totloop);
void create_vert_face_map(struct ListBase **map, IndexNode **mem, const struct MFace *mface,
const int totvert, const int totface);
void create_vert_edge_map(struct ListBase **map, IndexNode **mem, const struct MEdge *medge,
@ -203,11 +268,15 @@ void BKE_mesh_calc_edges(struct Mesh *mesh, int update);
void BKE_mesh_ensure_navmesh(struct Mesh *me);
void BKE_mesh_tessface_calc(struct Mesh *mesh);
void BKE_mesh_tessface_ensure(struct Mesh *mesh);
void BKE_mesh_tessface_clear(struct Mesh *mesh);
/*convert a triangle of loop facedata to mface facedata*/
void mesh_loops_to_mface_corners(struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int lindex[4], int findex,
const int polyindex, const int mf_len,
const int numTex, const int numCol, const int hasWCol);
const int numTex, const int numCol, const int hasWCol, const int hasOrigSpace);
#ifdef __cplusplus
}

@ -45,6 +45,7 @@ struct ListBase;
struct LinkNode;
struct bArmature;
struct ModifierData;
struct BMEditMesh;
typedef enum {
/* Should not be used, only for None modifier type */
@ -154,13 +155,13 @@ typedef struct ModifierTypeInfo {
*/
void (*deformVertsEM)(
struct ModifierData *md, struct Object *ob,
struct EditMesh *editData, struct DerivedMesh *derivedData,
struct BMEditMesh *editData, struct DerivedMesh *derivedData,
float (*vertexCos)[3], int numVerts);
/* Set deform matrix per vertex for crazyspace correction */
void (*deformMatricesEM)(
struct ModifierData *md, struct Object *ob,
struct EditMesh *editData, struct DerivedMesh *derivedData,
struct BMEditMesh *editData, struct DerivedMesh *derivedData,
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/********************* Non-deform modifier functions *********************/
@ -198,7 +199,7 @@ typedef struct ModifierTypeInfo {
*/
struct DerivedMesh *(*applyModifierEM)(
struct ModifierData *md, struct Object *ob,
struct EditMesh *editData,
struct BMEditMesh *editData,
struct DerivedMesh *derivedData);

@ -71,6 +71,14 @@ int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresMo
void multires_stitch_grids(struct Object *);
/*switch mdisp data in dm between tangent and object space*/
enum {
MULTIRES_SPACE_TANGENT,
MULTIRES_SPACE_OBJECT,
MULTIRES_SPACE_ABSOLUTE,
};
void multires_set_space(struct DerivedMesh *dm, struct Object *ob, int from, int to);
/* Related to the old multires */
void multires_free(struct Multires *mr);
void multires_load_old(struct Object *ob, struct Mesh *me);

@ -67,13 +67,14 @@ typedef struct SculptSession {
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
struct MultiresModifierData *multires; /* Special handling for multires meshes */
struct MVert *mvert;
struct MFace *mface;
int totvert, totface;
struct MPoly *mpoly;
struct MLoop *mloop;
int totvert, totpoly;
float *face_normals;
struct KeyBlock *kb;
/* Mesh connectivity */
struct ListBase *fmap;
struct ListBase *pmap;
/* PBVH acceleration structure */
struct PBVH *pbvh;

@ -46,6 +46,10 @@ struct _CCGEdge;
struct _CCGFace;
struct _CCGSubsurf;
struct _CCGVert;
struct EdgeHash;
struct PBVH;
struct DMGridData;
struct DMGridAdjacency;
/**************************** External *****************************/
@ -74,10 +78,15 @@ typedef struct CCGDerivedMesh {
short *edgeFlags;
char *faceFlags;
int *reverseFaceMap;
struct PBVH *pbvh;
struct ListBase *fmap;
struct IndexNode *fmap_mem;
struct ListBase *pmap;
struct IndexNode *pmap_mem;
struct DMGridData **gridData;
struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
@ -95,6 +104,8 @@ typedef struct CCGDerivedMesh {
void (*update)(DerivedMesh*);
} multires;
struct EdgeHash *ehash;
} CCGDerivedMesh;
#endif

@ -0,0 +1,94 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_TESSMESH_H__
#define __BKE_TESSMESH_H__
#include "bmesh.h"
struct BMesh;
struct BMLoop;
struct BMFace;
struct Mesh;
struct DerivedMesh;
/*
ok: the EDBM module is for editmode bmesh stuff. in contrast, the
BMEdit module is for code shared with blenkernel that concerns
the BMEditMesh structure.
*/
/*this structure replaces EditMesh.
through this, you get access to both the edit bmesh,
it's tesselation, and various stuff that doesn't belong in the BMesh
struct itself.
the entire derivedmesh and modifier system works with this structure,
and not BMesh. Mesh->edit_bmesh stores a pointer to this structure.*/
typedef struct BMEditMesh {
struct BMesh *bm;
/*this is for undoing failed operations*/
struct BMEditMesh *emcopy;
int emcopyusers;
/*we store tesselations as triplets of three loops,
which each define a triangle.*/
struct BMLoop *(*looptris)[3];
int tottri;
/*derivedmesh stuff*/
struct DerivedMesh *derivedFinal, *derivedCage;
int lastDataMask;
/* index tables, to map indices to elements via
* EDBM_init_index_arrays and associated functions. don't
* touch this or read it directly.*/
struct BMVert **vert_index;
struct BMEdge **edge_index;
struct BMFace **face_index;
/*selection mode*/
short selectmode;
short mat_nr;
/*Mesh structure this editmesh came from, if it came from one*/
struct Mesh *me;
struct Object *ob;
/*temp variables for x-mirror editing*/
int mirror_cdlayer; /* -1 is invalid */
int mirr_free_arrays;
} BMEditMesh;
/* undo triggers editmesh tessface update, this is odd but works OK.
* BMESH_TODO, look into having the update elsewhere. */
#define BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
void BMEdit_RecalcTesselation(BMEditMesh *tm);
BMEditMesh *BMEdit_Create(BMesh *bm, int do_tesselate);
BMEditMesh *BMEdit_Copy(BMEditMesh *tm);
void BMEdit_Free(BMEditMesh *em);
void BMEdit_UpdateLinkedCustomData(BMEditMesh *em);
#endif /* __BKE_TESSMESH_H__ */

@ -35,6 +35,7 @@ set(INC
../imbuf
../makesdna
../makesrna
../bmesh
../modifiers
../nodes
../render/extern/include
@ -58,12 +59,6 @@ set(INC_SYS
)
set(SRC
intern/BME_Customdata.c
intern/BME_conversions.c
intern/BME_eulers.c
intern/BME_mesh.c
intern/BME_structure.c
intern/BME_tools.c
intern/CCGSubSurf.c
intern/DerivedMesh.c
intern/action.c
@ -116,6 +111,7 @@ set(SRC
intern/mesh.c
intern/mesh_validate.c
intern/modifier.c
intern/modifiers_bmesh.c
intern/movieclip.c
intern/multires.c
intern/nla.c
@ -230,6 +226,7 @@ set(SRC
BKE_speaker.h
BKE_subsurf.h
BKE_suggestions.h
BKE_tessmesh.h
BKE_text.h
BKE_texture.h
BKE_tracking.h

@ -12,6 +12,7 @@ incs += ' #/intern/iksolver/extern ../blenloader ../freestyle'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
incs += ' ../bmesh'
incs += ' #/intern/smoke/extern'
incs += ' #/intern/mikktspace'
incs += ' #/intern/audaspace/intern'

@ -1,198 +0,0 @@
/*
* BME_customdata.c jan 2007
*
* Custom Data functions for Bmesh
*
*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2004 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle, Brecht Van Lommel, Ben Batt
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_Customdata.c
* \ingroup bke
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BKE_bmeshCustomData.h"
#include "bmesh_private.h"
/********************* Layer type information **********************/
typedef struct BME_LayerTypeInfo {
int size;
const char *defaultname;
void (*copy)(const void *source, void *dest, int count);
void (*free)(void *data, int count, int size);
void (*interp)(void **sources, float *weights, float *sub_weights, int count, void *dest);
void (*set_default)(void *data, int count);
} BME_LayerTypeInfo;
const BME_LayerTypeInfo BMELAYERTYPEINFO[BME_CD_NUMTYPES] = {
{sizeof(BME_facetex), "TexFace", NULL, NULL, NULL, NULL},
{sizeof(BME_looptex), "UV", NULL, NULL, NULL, NULL},
{sizeof(BME_loopcol), "VCol", NULL, NULL, NULL, NULL},
{sizeof(BME_DeformVert), "Group", NULL, NULL, NULL, NULL}
};
static const BME_LayerTypeInfo *BME_layerType_getInfo(int type)
{
if(type < 0 || type >= CD_NUMTYPES) return NULL;
return &BMELAYERTYPEINFO[type];
}
void BME_CD_Create(BME_CustomData *data, BME_CustomDataInit *init, int initalloc)
{
int i, j, offset=0;
const BME_LayerTypeInfo *info;
/*initialize data members*/
data->layers = NULL;
data->pool = NULL;
data->totlayer = 0;
data->totsize = 0;
/*first count how many layers to alloc*/
for(i=0; i < BME_CD_NUMTYPES; i++){
info = BME_layerType_getInfo(i);
data->totlayer += init->layout[i];
data->totsize += (init->layout[i] * info->size);
}
/*alloc our layers*/
if(data->totlayer){
/*alloc memory*/
data->layers = MEM_callocN(sizeof(BME_CustomDataLayer)*data->totlayer, "BMesh Custom Data Layers");
data->pool = BLI_mempool_create(data->totsize, initalloc, initalloc, FALSE, FALSE);
/*initialize layer data*/
for(i=0; i < BME_CD_NUMTYPES; i++){
if(init->layout[i]){
info = BME_layerType_getInfo(i);
for(j=0; j < init->layout[i]; j++){
if(j==0) data->layers[j+i].active = init->active[i];
data->layers[j+i].type = i;
data->layers[j+i].offset = offset;
strcpy(data->layers[j+i].name, &(init->nametemplate[j+i]));
offset += info->size;
}
}
}
}
}
void BME_CD_Free(BME_CustomData *data)
{
if(data->pool) BLI_mempool_destroy(data->pool);
}
/*Block level ops*/
void BME_CD_free_block(BME_CustomData *data, void **block)
{
const BME_LayerTypeInfo *typeInfo;
int i;
if(!*block) return;
for(i = 0; i < data->totlayer; ++i) {
typeInfo = BME_layerType_getInfo(data->layers[i].type);
if(typeInfo->free) {
int offset = data->layers[i].offset;
typeInfo->free((char*)*block + offset, 1, typeInfo->size);
}
}
BLI_mempool_free(data->pool, *block);
*block = NULL;
}
static void BME_CD_alloc_block(BME_CustomData *data, void **block)
{
if (*block) BME_CD_free_block(data, block); //if we copy layers that have their own free functions like deformverts
if (data->totsize > 0)
*block = BLI_mempool_alloc(data->pool);
else
*block = NULL;
}
void BME_CD_copy_data(const BME_CustomData *source, BME_CustomData *dest,
void *src_block, void **dest_block)
{
const BME_LayerTypeInfo *typeInfo;
int dest_i, src_i;
if (!*dest_block) /*for addXXXlist functions!*/
BME_CD_alloc_block(dest, dest_block);
/* copies a layer at a time */
dest_i = 0;
for(src_i = 0; src_i < source->totlayer; ++src_i) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while(dest_i < dest->totlayer
&& dest->layers[dest_i].type < source->layers[src_i].type)
++dest_i;
/* if there are no more dest layers, we're done */
if(dest_i >= dest->totlayer) return;
/* if we found a matching layer, copy the data */
if(dest->layers[dest_i].type == source->layers[src_i].type &&
strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0) {
char *src_data = (char*)src_block + source->layers[src_i].offset;
char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset;
typeInfo = BME_layerType_getInfo(source->layers[src_i].type);
if(typeInfo->copy)
typeInfo->copy(src_data, dest_data, 1);
else
memcpy(dest_data, src_data, typeInfo->size);
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
++dest_i;
}
}
}
void BME_CD_set_default(BME_CustomData *data, void **block)
{
const BME_LayerTypeInfo *typeInfo;
int i;
if (!*block)
BME_CD_alloc_block(data, block); //for addXXXlist functions...
for(i = 0; i < data->totlayer; ++i) {
int offset = data->layers[i].offset;
typeInfo = BME_layerType_getInfo(data->layers[i].type);
if(typeInfo->set_default)
typeInfo->set_default((char*)*block + offset, 1);
}
}

@ -1,650 +0,0 @@
/*
* BME_mesh.c jan 2007
*
* BMesh mesh level functions.
*
*
* ***** 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.
* about this.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle, Levi Schooley.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_conversions.c
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_mesh.h"
#include "BKE_cdderivedmesh.h"
//XXX #include "BIF_editmesh.h"
//XXX #include "editmesh.h"
#include "bmesh_private.h"
//XXX #include "BSE_edit.h"
/* XXX IMPORTANT: editmesh stuff doesn't belong in kernel! (ton) */
/*merge these functions*/
static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i< numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texpoly->tpage = texface[index].tpage;
texpoly->flag = texface[index].flag;
texpoly->transp = texface[index].transp;
texpoly->mode = texface[index].mode;
texpoly->tile = texface[index].tile;
texpoly->unwrap = texface[index].unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
mloopuv->uv[0] = texface[index].uv[j][0];
mloopuv->uv[1] = texface[index].uv[j][1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mloopcol->r = mcol[(index*4)+j].r;
mloopcol->g = mcol[(index*4)+j].g;
mloopcol->b = mcol[(index*4)+j].b;
mloopcol->a = mcol[(index*4)+j].a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_DMloops_to_corners(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texface[index].tpage = texpoly->tpage;
texface[index].flag = texpoly->flag;
texface[index].transp = texpoly->transp;
texface[index].mode = texpoly->mode;
texface[index].tile = texpoly->tile;
texface[index].unwrap = texpoly->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
texface[index].uv[j][0] = mloopuv->uv[0];
texface[index].uv[j][1] = mloopuv->uv[1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mcol[(index*4) + j].r = mloopcol->r;
mcol[(index*4) + j].g = mloopcol->g;
mcol[(index*4) + j].b = mloopcol->b;
mcol[(index*4) + j].a = mloopcol->a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_corners_to_loops(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texpoly->tpage = texface->tpage;
texpoly->flag = texface->flag;
texpoly->transp = texface->transp;
texpoly->mode = texface->mode;
texpoly->tile = texface->tile;
texpoly->unwrap = texface->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
mloopuv->uv[0] = texface->uv[j][0];
mloopuv->uv[1] = texface->uv[j][1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mloopcol->r = mcol[j].r;
mloopcol->g = mcol[j].g;
mloopcol->b = mcol[j].b;
mloopcol->a = mcol[j].a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_loops_to_corners(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texface->tpage = texpoly->tpage;
texface->flag = texpoly->flag;
texface->transp = texpoly->transp;
texface->mode = texpoly->mode;
texface->tile = texpoly->tile;
texface->unwrap = texpoly->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
texface->uv[j][0] = mloopuv->uv[0];
texface->uv[j][1] = mloopuv->uv[1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mcol[j].r = mloopcol->r;
mcol[j].g = mloopcol->g;
mcol[j].b = mloopcol->b;
mcol[j].a = mloopcol->a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
/*move the EditMesh conversion functions to editmesh_tools.c*/
BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
BME_Mesh *bm;
int allocsize[4] = {512,512,2048,512}, numTex, numCol;
BME_Vert *v1, *v2;
BME_Edge *e, *edar[4];
BME_Poly *f;
EditVert *eve;
EditEdge *eed;
EditFace *efa;
int len;
bm = BME_make_mesh(allocsize);
/*copy custom data layout*/
CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
/*needed later*/
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
BME_model_begin(bm);
/*add verts*/
eve= em->verts.first;
while(eve) {
v1 = BME_MV(bm,eve->co);
VECCOPY(v1->no,eve->no);
v1->flag = eve->f;
v1->h = eve->h;
v1->bweight = eve->bweight;
/*Copy Custom Data*/
CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data);
eve->tmp.v = (EditVert*)v1;
eve = eve->next;
}
/*add edges*/
eed= em->edges.first;
while(eed) {
v1 = (BME_Vert*)eed->v1->tmp.v;
v2 = (BME_Vert*)eed->v2->tmp.v;
e = BME_ME(bm, v1, v2);
e->crease = eed->crease;
e->bweight = eed->bweight;
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;
CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data);
eed = eed->next;
}
/*add faces.*/
efa= em->faces.first;
while(efa) {
if(efa->v4) len = 4;
else len = 3;
edar[0] = (BME_Edge*)efa->e1->tmp.e;
edar[1] = (BME_Edge*)efa->e2->tmp.e;
edar[2] = (BME_Edge*)efa->e3->tmp.e;
if(len == 4){
edar[3] = (BME_Edge*)efa->e4->tmp.e;
}
/*find v1 and v2*/
v1 = (BME_Vert*)efa->v1->tmp.v;
v2 = (BME_Vert*)efa->v2->tmp.v;
f = BME_MF(bm,v1,v2,edar,len);
f->mat_nr = efa->mat_nr;
f->flag = efa->flag;
if(efa->h) {
f->flag |= ME_HIDE;
f->flag &= ~ME_FACE_SEL;
}
else {
if(efa->f & 1) f->flag |= ME_FACE_SEL;
else f->flag &= ~ME_FACE_SEL;
}
CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
BME_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
efa = efa->next;
}
BME_model_end(bm);
return bm;
}
/* adds the geometry in the bmesh to editMesh (does not free editMesh)
* if td != NULL, the transdata will be mapped to the EditVert's co */
void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
BME_Vert *v1;
BME_Edge *e;
BME_Poly *f;
BME_TransData *vtd;
EditVert *eve1, /* *eve2, *eve3, *eve4, */ /* UNUSED */ **evlist;
EditEdge *eed;
EditFace *efa;
int totvert, len, i, numTex, numCol;
if (em == NULL) return;
CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
/* convert to EditMesh */
/* make editverts */
totvert = BLI_countlist(&(bm->verts));
evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist");
for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) {
v1->tflag1 = i;
eve1 = NULL; //XXX addvertlist(v1->co,NULL);
if (td && (vtd = BME_get_transdata(td,v1))) {
vtd->loc = eve1->co;
}
eve1->keyindex = i;
evlist[i]= eve1;
eve1->f = (unsigned char)v1->flag;
eve1->h = (unsigned char)v1->h;
eve1->bweight = v1->bweight;
CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data);
}
/* make edges */
for (e=bm->edges.first;e;e=e->next) {
if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){
eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL);
eed->crease = e->crease;
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;
if(em->selectmode==SCE_SELECT_EDGE) {
; //XXX EM_select_edge(eed, eed->f & SELECT);
}
CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
}
}
/* make faces */
for (f=bm->polys.first;f;f=f->next) {
len = BME_cycle_length(f->loopbase);
if (len==3 || len==4) {
eve1= evlist[f->loopbase->v->tflag1];
/* eve2= evlist[f->loopbase->next->v->tflag1]; */ /* UNUSED */
/* eve3= evlist[f->loopbase->next->next->v->tflag1]; */ /* UNUSED */
/* if (len == 4) {
eve4= evlist[f->loopbase->prev->v->tflag1];
}
else {
eve4= NULL;
} */ /* UNUSED */
efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
efa->mat_nr = (unsigned char)f->mat_nr;
efa->flag= f->flag & ~ME_HIDE;
if(f->flag & ME_FACE_SEL) {
efa->f |= SELECT;
}
if(f->flag & ME_HIDE) efa->h= 1;
// XXX flag depricated
// if((G.f & G_FACESELECT) && (efa->f & SELECT))
//XXX EM_select_face(efa, 1); /* flush down */
CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex);
}
}
MEM_freeN(evlist);
}
/* Adds the geometry found in dm to bm
*/
BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
{
BME_Mesh *bm;
int allocsize[4] = {512,512,2048,512};
MVert *mvert, *mv;
MEdge *medge, *me;
MFace *mface, *mf;
int totface,totedge,totvert,i,len, numTex, numCol;
BME_Vert *v1=NULL,*v2=NULL, **vert_array;
BME_Edge *e=NULL;
BME_Poly *f=NULL;
EdgeHash *edge_hash = BLI_edgehash_new();
bm = BME_make_mesh(allocsize);
/*copy custom data layout*/
CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
/*needed later*/
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumFaces(dm);
mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
mface = dm->getFaceArray(dm);
vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
BME_model_begin(bm);
/*add verts*/
for(i=0,mv = mvert; i < totvert;i++,mv++){
v1 = BME_MV(bm,mv->co);
vert_array[i] = v1;
v1->flag = mv->flag;
v1->bweight = mv->bweight/255.0f;
CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v1->data);
}
/*add edges*/
for(i=0,me = medge; i < totedge;i++,me++){
v1 = vert_array[me->v1];
v2 = vert_array[me->v2];
e = BME_ME(bm, v1, v2);
e->crease = me->crease/255.0f;
e->bweight = me->bweight/255.0f;
e->flag = (unsigned char)me->flag;
BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->data);
}
/*add faces.*/
for(i=0,mf = mface; i < totface;i++,mf++){
BME_Edge *edar[4];
if(mf->v4) len = 4;
else len = 3;
edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
if(len == 4){
edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
}
else
edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
/*find v1 and v2*/
v1 = vert_array[mf->v1];
v2 = vert_array[mf->v2];
f = BME_MF(bm,v1,v2,edar,len);
f->mat_nr = mf->mat_nr;
f->flag = mf->flag;
CustomData_to_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data);
BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex);
}
BME_model_end(bm);
BLI_edgehash_free(edge_hash, NULL);
MEM_freeN(vert_array);
return bm;
}
DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
{
MFace *mface, *mf;
MEdge *medge, *me;
MVert *mvert, *mv;
int *origindex;
int totface, totedge, totvert, i, /* bmeshok, */ /* UNUSED */ len, numTex, numCol;
BME_Vert *v1=NULL;
BME_Edge *e=NULL, *oe=NULL;
BME_Poly *f=NULL;
DerivedMesh *result;
EdgeHash *edge_hash = BLI_edgehash_new();
totvert = BLI_countlist(&(bm->verts));
totedge = 0;
/*we cannot have double edges in a derived mesh!*/
for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i;
for(e=bm->edges.first; e; e=e->next){
oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1);
if(!oe){
totedge++;
BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e);
e->tflag2 = 1;
}
else{
e->tflag2 = 0;
}
}
/*count quads and tris*/
totface = 0;
/* bmeshok = 1; */ /* UNUSED */
for(f=bm->polys.first;f;f=f->next){
len = BME_cycle_length(f->loopbase);
if(len == 3 || len == 4) totface++;
}
/*convert back to mesh*/
result = CDDM_from_template(dm,totvert,totedge,totface);
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
/*Make Verts*/
mvert = CDDM_get_verts(result);
origindex = result->getVertDataArray(result, CD_ORIGINDEX);
for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
VECCOPY(mv->co,v1->co);
mv->flag = (unsigned char)v1->flag;
mv->bweight = (char)(255.0*v1->bweight);
CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i);
origindex[i] = ORIGINDEX_NONE;
}
medge = CDDM_get_edges(result);
origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
i=0;
for(e=bm->edges.first,me=medge;e;e=e->next){
if(e->tflag2){
if(e->v1->tflag1 < e->v2->tflag1){
me->v1 = e->v1->tflag1;
me->v2 = e->v2->tflag1;
}
else{
me->v1 = e->v2->tflag1;
me->v2 = e->v1->tflag1;
}
me->crease = (char)(255.0*e->crease);
me->bweight = (char)(255.0*e->bweight);
me->flag = e->flag;
CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i);
origindex[i] = ORIGINDEX_NONE;
me++;
i++;
}
}
if(totface){
mface = CDDM_get_faces(result);
origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
/*make faces*/
for(i=0,f=bm->polys.first;f;f=f->next){
mf = &mface[i];
len = BME_cycle_length(f->loopbase);
if(len==3 || len==4){
mf->v1 = f->loopbase->v->tflag1;
mf->v2 = f->loopbase->next->v->tflag1;
mf->v3 = f->loopbase->next->next->v->tflag1;
if(len == 4){
mf->v4 = f->loopbase->prev->v->tflag1;
}
/* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){
test_index_face(mf, NULL, i, len);
}
mf->mat_nr = (unsigned char)f->mat_nr;
mf->flag = (unsigned char)f->flag;
CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i);
BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex);
origindex[i] = ORIGINDEX_NONE;
i++;
}
}
}
BLI_edgehash_free(edge_hash, NULL);
return result;
}

@ -1,973 +0,0 @@
/*
* BME_eulers.c jan 2007
*
* BMesh Euler construction API.
*
*
* ***** 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.
* about this.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2004 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_eulers.c
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "bmesh_private.h"
/*********************************************************
* "Euler API" *
* *
* *
* Primitive construction operators for mesh tools. *
* *
**********************************************************/
/*
The functions in this file represent the 'primitive' or 'atomic' operators that
mesh tools use to manipulate the topology of the structure.* The purpose of these
functions is to provide a trusted set of operators to manipulate the mesh topology
and which can also be combined together like building blocks to create more
sophisticated tools. It needs to be stressed that NO manipulation of an existing
mesh structure should be done outside of these functions.
In the BMesh system, each euler is named by an ancronym which describes what it actually does.
Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
through a Euler's logical inverse you can 'undo' an operation. (Special note should
be taken of BME_loop_reverse, which is its own inverse).
BME_MF/KF: Make Face and Kill Face
BME_ME/KE: Make Edge and Kill Edge
BME_MV/KV: Make Vert and Kill Vert
BME_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
BME_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
BME_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
Each Euler operator has a detailed explanation of what is does in the comments preceding its
code.
*The term "Euler Operator" is actually a misnomer when referring to a non-manifold
data structure. Its use is in keeping with the convention established by others.
TODO:
-Finish inserting 'strict' validation in all Eulers
*/
void *BME_exit(char *s) {
if (s) printf("%s\n",s);
return NULL;
}
#define RETCLEAR(bm) {bm->rval->v = bm->rval->e = bm->rval->f = bm->rva->l = NULL;}
/*MAKE Eulers*/
/**
* BME_MV
*
* MAKE VERT EULER:
*
* Makes a single loose vertex.
*
* Returns -
* A BME_Vert pointer.
*/
BME_Vert *BME_MV(BME_Mesh *bm, float *vec){
BME_Vert *v = BME_addvertlist(bm, NULL);
VECCOPY(v->co,vec);
return v;
}
/**
* BME_ME
*
* MAKE EDGE EULER:
*
* Makes a single wire edge between two vertices.
* If the caller does not want there to be duplicate
* edges between the vertices, it is up to them to check
* for this condition beforehand.
*
* Returns -
* A BME_Edge pointer.
*/
BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){
BME_Edge *e=NULL;
BME_CycleNode *d1=NULL, *d2=NULL;
int valance1=0, valance2=0, edok;
/*edge must be between two distinct vertices...*/
if(v1 == v2) return NULL;
#ifndef BME_FASTEULER
/*count valance of v1*/
if(v1->edge){
d1 = BME_disk_getpointer(v1->edge,v1);
if(d1) valance1 = BME_cycle_length(d1);
else BME_error();
}
if(v2->edge){
d2 = BME_disk_getpointer(v2->edge,v2);
if(d2) valance2 = BME_cycle_length(d2);
else BME_error();
}
#endif
/*go ahead and add*/
e = BME_addedgelist(bm, v1, v2, NULL);
BME_disk_append_edge(e, e->v1);
BME_disk_append_edge(e, e->v2);
#ifndef BME_FASTEULER
/*verify disk cycle lengths*/
d1 = BME_disk_getpointer(e, e->v1);
edok = BME_cycle_validate(valance1+1, d1);
if(!edok) BME_error();
d2 = BME_disk_getpointer(e, e->v2);
edok = BME_cycle_validate(valance2+1, d2);
if(!edok) BME_error();
/*verify that edge actually made it into the cycle*/
edok = BME_disk_hasedge(v1, e);
if(!edok) BME_error();
edok = BME_disk_hasedge(v2, e);
if(!edok) BME_error();
#endif
return e;
}
/**
* BME_MF
*
* MAKE FACE EULER:
* Takes a list of edge pointers which form a closed loop and makes a face
* from them. The first edge in elist is considered to be the start of the
* polygon, and v1 and v2 are its vertices and determine the winding of the face
* Other than the first edge, no other assumptions are made about the order of edges
* in the elist array. To verify that it is a single closed loop and derive the correct
* order a simple series of verifications is done and all elements are visited.
*
* Returns -
* A BME_Poly pointer
*/
#define MF_CANDIDATE 1
#define MF_VISITED 2
#define MF_TAKEN 4
BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len)
{
BME_Poly *f = NULL;
BME_Edge *curedge;
BME_Vert *curvert, *tv, **vlist;
int i, j, done, cont, edok;
if(len < 2) return NULL;
/*make sure that v1 and v2 are in elist[0]*/
if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return NULL;
/*clear euler flags*/
for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0;
for(i=0;i<len;i++){
elist[i]->eflag1 |= MF_CANDIDATE;
/*if elist[i] has a loop, count its radial length*/
if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial));
else elist[i]->eflag2 = 0;
}
/* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
that elist contains a finite number of seperate closed loops.
*/
for(i=0; i<len; i++){
edok = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
if(edok != 2) return NULL;
edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
if(edok != 2) return NULL;
}
/*set start edge, start vert and target vert for our loop traversal*/
curedge = elist[0];
tv = v1;
curvert = v2;
if(bm->vtarlen < len){
MEM_freeN(bm->vtar);
bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh Vert pointer array");
bm->vtarlen = len;
}
/*insert tv into vlist since its the first vertex in face*/
i=0;
vlist=bm->vtar;
vlist[i] = tv;
/* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't
been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
edge, loop until we find TV. We know TV is reachable because of test we did earlier.
*/
done=0;
while(!done){
/*add curvert to vlist*/
/*insert some error cheking here for overflows*/
i++;
vlist[i] = curvert;
/*mark curedge as visited*/
curedge->eflag1 |= MF_VISITED;
/*find next edge and vert*/
curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
curvert = BME_edge_getothervert(curedge, curvert);
if(curvert == tv){
curedge->eflag1 |= MF_VISITED;
done=1;
}
}
/* Verify that all edges have been visited It's possible that we did reach tv
from sv, but that several unconnected loops were passed in via elist.
*/
cont=1;
for(i=0; i<len; i++){
if((elist[i]->eflag1 & MF_VISITED) == 0) cont = 0;
}
/*if we get this far, its ok to allocate the face and add the loops*/
if(cont){
BME_Loop *l;
BME_Edge *e;
f = BME_addpolylist(bm, NULL);
f->len = len;
for(i=0;i<len;i++){
curvert = vlist[i];
l = BME_create_loop(bm,curvert,NULL,f,NULL);
if(!(f->loopbase)) f->loopbase = l;
BME_cycle_append(f->loopbase, l);
}
/*take care of edge pointers and radial cycle*/
for(i=0, l = f->loopbase; i<len; i++, l=l->next){
e = NULL;
if(l == f->loopbase) e = elist[0]; /*first edge*/
else{/*search elist for others*/
for(j=1; j<len; j++){
edok = BME_verts_in_edge(l->v, l->next->v, elist[j]);
if(edok){
e = elist[j];
break;
}
}
}
l->e = e; /*set pointer*/
BME_radial_append(e, l); /*append into radial*/
}
f->len = len;
/*Validation Loop cycle*/
edok = BME_cycle_validate(len, f->loopbase);
if(!edok) BME_error();
for(i=0, l = f->loopbase; i<len; i++, l=l->next){
/*validate loop vert pointers*/
edok = BME_verts_in_edge(l->v, l->next->v, l->e);
if(!edok) BME_error();
/*validate the radial cycle of each edge*/
edok = BME_cycle_length(&(l->radial));
if(edok != (l->e->eflag2 + 1)) BME_error();
}
}
return f;
}
/* KILL Eulers */
/**
* BME_KV
*
* KILL VERT EULER:
*
* Kills a single loose vertex.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_KV(BME_Mesh *bm, BME_Vert *v){
if(v->edge == NULL){
BLI_remlink(&(bm->verts), v);
BME_free_vert(bm,v);
return 1;
}
return 0;
}
/**
* BME_KE
*
* KILL EDGE EULER:
*
* Kills a wire edge.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_KE(BME_Mesh *bm, BME_Edge *e){
int edok;
/*Make sure that no faces!*/
if(e->loop == NULL){
BME_disk_remove_edge(e, e->v1);
BME_disk_remove_edge(e, e->v2);
/*verify that edge out of disk*/
edok = BME_disk_hasedge(e->v1, e);
if(edok) BME_error();
edok = BME_disk_hasedge(e->v2, e);
if(edok) BME_error();
/*remove and deallocate*/
BLI_remlink(&(bm->edges), e);
BME_free_edge(bm, e);
return 1;
}
return 0;
}
/**
* BME_KF
*
* KILL FACE EULER:
*
* The logical inverse of BME_MF.
* Kills a face and removes each of its loops from the radial that it belongs to.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_KF(BME_Mesh *bm, BME_Poly *bply){
BME_Loop *newbase,*oldbase, *curloop;
int i,len=0;
/*add validation to make sure that radial cycle is cleaned up ok*/
/*deal with radial cycle first*/
len = BME_cycle_length(bply->loopbase);
for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next)
BME_radial_remove_loop(curloop, curloop->e);
/*now deallocate the editloops*/
for(i=0; i < len; i++){
newbase = bply->loopbase->next;
oldbase = bply->loopbase;
BME_cycle_remove(oldbase, oldbase);
BME_free_loop(bm, oldbase);
bply->loopbase = newbase;
}
BLI_remlink(&(bm->polys), bply);
BME_free_poly(bm, bply);
return 1;
}
/*SPLIT Eulers*/
/**
* BME_SEMV
*
* SPLIT EDGE MAKE VERT:
* Takes a given edge and splits it into two, creating a new vert.
*
*
* Before: OV---------TV
* After: OV----NV---TV
*
* Returns -
* BME_Vert pointer.
*
*/
BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
BME_Vert *nv, *ov;
BME_CycleNode *diskbase;
BME_Edge *ne;
int i, edok, valance1=0, valance2=0;
if(BME_vert_in_edge(e,tv) == 0) return NULL;
ov = BME_edge_getothervert(e,tv);
//v2 = tv;
/*count valance of v1*/
diskbase = BME_disk_getpointer(e, ov);
valance1 = BME_cycle_length(diskbase);
/*count valance of v2*/
diskbase = BME_disk_getpointer(e, tv);
valance2 = BME_cycle_length(diskbase);
nv = BME_addvertlist(bm, tv);
ne = BME_addedgelist(bm, nv, tv, e);
//e->v2 = nv;
/*remove e from v2's disk cycle*/
BME_disk_remove_edge(e, tv);
/*swap out tv for nv in e*/
BME_edge_swapverts(e, tv, nv);
/*add e to nv's disk cycle*/
BME_disk_append_edge(e, nv);
/*add ne to nv's disk cycle*/
BME_disk_append_edge(ne, nv);
/*add ne to tv's disk cycle*/
BME_disk_append_edge(ne, tv);
/*verify disk cycles*/
diskbase = BME_disk_getpointer(ov->edge,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(tv->edge,tv);
edok = BME_cycle_validate(valance2, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(nv->edge,nv);
edok = BME_cycle_validate(2, diskbase);
if(!edok) BME_error();
/*Split the radial cycle if present*/
if(e->loop){
BME_Loop *nl,*l;
BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
int radlen = BME_cycle_length(&(e->loop->radial));
/*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
while(e->loop){
l=e->loop;
l->f->len++;
BME_radial_remove_loop(l,e);
nl = BME_create_loop(bm,NULL,NULL,l->f,l);
nl->prev = l;
nl->next = l->next;
nl->prev->next = nl;
nl->next->prev = nl;
nl->v = nv;
/*assign the correct edge to the correct loop*/
if(BME_verts_in_edge(nl->v, nl->next->v, e)){
nl->e = e;
l->e = ne;
/*append l into ne's rad cycle*/
if(!radNEBase){
radNEBase = &(l->radial);
radNEBase->next = NULL;
radNEBase->prev = NULL;
}
if(!radEBase){
radEBase = &(nl->radial);
radEBase->next = NULL;
radEBase->prev = NULL;
}
BME_cycle_append(radEBase,&(nl->radial));
BME_cycle_append(radNEBase,&(l->radial));
}
else if(BME_verts_in_edge(nl->v,nl->next->v,ne)){
nl->e = ne;
l->e = e;
if(!radNEBase){
radNEBase = &(nl->radial);
radNEBase->next = NULL;
radNEBase->prev = NULL;
}
if(!radEBase){
radEBase = &(l->radial);
radEBase->next = NULL;
radEBase->prev = NULL;
}
BME_cycle_append(radEBase,&(l->radial));
BME_cycle_append(radNEBase,&(nl->radial));
}
}
e->loop = radEBase->data;
ne->loop = radNEBase->data;
/*verify length of radial cycle*/
edok = BME_cycle_validate(radlen,&(e->loop->radial));
if(!edok) BME_error();
edok = BME_cycle_validate(radlen,&(ne->loop->radial));
if(!edok) BME_error();
/*verify loop->v and loop->next->v pointers for e*/
for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){
if(!(l->e == e)) BME_error();
if(!(l->radial.data == l)) BME_error();
if(l->prev->e != ne && l->next->e != ne) BME_error();
edok = BME_verts_in_edge(l->v, l->next->v, e);
if(!edok) BME_error();
if(l->v == l->next->v) BME_error();
if(l->e == l->next->e) BME_error();
/*verify loop cycle for kloop->f*/
edok = BME_cycle_validate(l->f->len, l->f->loopbase);
if(!edok) BME_error();
}
/*verify loop->v and loop->next->v pointers for ne*/
for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){
if(!(l->e == ne)) BME_error();
if(!(l->radial.data == l)) BME_error();
if(l->prev->e != e && l->next->e != e) BME_error();
edok = BME_verts_in_edge(l->v, l->next->v, ne);
if(!edok) BME_error();
if(l->v == l->next->v) BME_error();
if(l->e == l->next->e) BME_error();
/*verify loop cycle for kloop->f. Redundant*/
edok = BME_cycle_validate(l->f->len, l->f->loopbase);
if(!edok) BME_error();
}
}
if(re) *re = ne;
return nv;
}
/**
* BME_SFME
*
* SPLIT FACE MAKE EDGE:
*
* Takes as input two vertices in a single face. An edge is created which divides the original face
* into two distinct regions. One of the regions is assigned to the original face and it is closed off.
* The second region has a new face assigned to it.
*
* Examples:
*
* Before: After:
* ---------- ----------
* | | | |
* | | | f1 |
* v1 f1 v2 v1======v2
* | | | f2 |
* | | | |
* ---------- ----------
*
* Note that the input vertices can be part of the same edge. This will result in a two edged face.
* This is desirable for advanced construction tools and particularly essential for edge bevel. Because
* of this it is up to the caller to decide what to do with the extra edge.
*
* Returns -
* A BME_Poly pointer
*/
BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){
BME_Poly *f2;
BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
BME_Edge *e;
int i, len, f1len, f2len;
/*verify that v1 and v2 are in face.*/
len = BME_cycle_length(f->loopbase);
for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){
if(curloop->v == v1) v1loop = curloop;
else if(curloop->v == v2) v2loop = curloop;
}
if(!v1loop || !v2loop) return NULL;
/*allocate new edge between v1 and v2*/
e = BME_addedgelist(bm, v1, v2,NULL);
BME_disk_append_edge(e, v1);
BME_disk_append_edge(e, v2);
f2 = BME_addpolylist(bm,f);
f1loop = BME_create_loop(bm,v2,e,f,v2loop);
f2loop = BME_create_loop(bm,v1,e,f2,v1loop);
f1loop->prev = v2loop->prev;
f2loop->prev = v1loop->prev;
v2loop->prev->next = f1loop;
v1loop->prev->next = f2loop;
f1loop->next = v1loop;
f2loop->next = v2loop;
v1loop->prev = f1loop;
v2loop->prev = f2loop;
f2->loopbase = f2loop;
f->loopbase = f1loop;
/*validate both loops*/
/*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
/*go through all of f2's loops and make sure they point to it properly.*/
f2len = BME_cycle_length(f2->loopbase);
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2;
/*link up the new loops into the new edges radial*/
BME_radial_append(e, f1loop);
BME_radial_append(e, f2loop);
f2->len = f2len;
f1len = BME_cycle_length(f->loopbase);
f->len = f1len;
if(rl) *rl = f2loop;
return f2;
}
/**
* BME_JEKV
*
* JOIN EDGE KILL VERT:
* Takes a an edge and pointer to one of its vertices and collapses
* the edge on that vertex.
*
* Before: OE KE
* ------- -------
* | || |
* OV KV TV
*
*
* After: OE
* ---------------
* | |
* OV TV
*
*
* Restrictions:
* KV is a vertex that must have a valance of exactly two. Furthermore
* both edges in KV's disk cycle (OE and KE) must be unique (no double
* edges).
*
* It should also be noted that this euler has the possibility of creating
* faces with just 2 edges. It is up to the caller to decide what to do with
* these faces.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
{
BME_Edge *oe;
BME_Vert *ov, *tv;
BME_CycleNode *diskbase;
BME_Loop *killoop,*nextl;
int len,radlen=0, halt = 0, i, valance1, valance2,edok;
if(BME_vert_in_edge(ke,kv) == 0) return 0;
diskbase = BME_disk_getpointer(kv->edge, kv);
len = BME_cycle_length(diskbase);
if(len == 2){
oe = BME_disk_nextedge(ke, kv);
tv = BME_edge_getothervert(ke, kv);
ov = BME_edge_getothervert(oe, kv);
halt = BME_verts_in_edge(kv, tv, oe); //check for double edges
if(halt) return 0;
else{
/*For verification later, count valance of ov and tv*/
diskbase = BME_disk_getpointer(ov->edge, ov);
valance1 = BME_cycle_length(diskbase);
diskbase = BME_disk_getpointer(tv->edge, tv);
valance2 = BME_cycle_length(diskbase);
/*remove oe from kv's disk cycle*/
BME_disk_remove_edge(oe,kv);
/*relink oe->kv to be oe->tv*/
BME_edge_swapverts(oe, kv, tv);
/*append oe to tv's disk cycle*/
BME_disk_append_edge(oe, tv);
/*remove ke from tv's disk cycle*/
BME_disk_remove_edge(ke, tv);
/*deal with radial cycle of ke*/
if(ke->loop){
/*first step, fix the neighboring loops of all loops in ke's radial cycle*/
radlen = BME_cycle_length(&(ke->loop->radial));
for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){
/*relink loops and fix vertex pointer*/
killoop->next->prev = killoop->prev;
killoop->prev->next = killoop->next;
if(killoop->next->v == kv) killoop->next->v = tv;
/*fix len attribute of face*/
killoop->f->len--;
if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next;
}
/*second step, remove all the hanging loops attached to ke*/
killoop = ke->loop;
radlen = BME_cycle_length(&(ke->loop->radial));
/*make sure we have enough room in bm->lpar*/
if(bm->lparlen < radlen){
MEM_freeN(bm->lpar);
bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array");
bm->lparlen = bm->lparlen * radlen;
}
/*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/
i=0;
while(i<radlen){
bm->lpar[i] = killoop;
killoop = killoop->radial.next->data;
i++;
}
i=0;
while(i<radlen){
BME_free_loop(bm,bm->lpar[i]);
i++;
}
/*Validate radial cycle of oe*/
edok = BME_cycle_validate(radlen,&(oe->loop->radial));
}
/*Validate disk cycles*/
diskbase = BME_disk_getpointer(ov->edge,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(tv->edge,tv);
edok = BME_cycle_validate(valance2, diskbase);
if(!edok) BME_error();
/*Validate loop cycle of all faces attached to oe*/
for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase);
if(!edok) BME_error();
}
/*deallocate edge*/
BLI_remlink(&(bm->edges), ke);
BME_free_edge(bm, ke);
/*deallocate vertex*/
BLI_remlink(&(bm->verts), kv);
BME_free_vert(bm, kv);
return 1;
}
}
return 0;
}
/**
* BME_loop_reverse
*
* FLIP FACE EULER
*
* Changes the winding order of a face from CW to CCW or vice versa.
* This euler is a bit peculiar in compairson to others as it is its
* own inverse.
*
* TODO: reinsert validation code.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){
BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext;
int i, j, edok, len = 0;
len = BME_cycle_length(l);
if(bm->edarlen < len){
MEM_freeN(bm->edar);
bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array");
bm->edarlen = len;
}
for(i=0, curloop = l; i< len; i++, curloop=curloop->next){
curloop->e->eflag1 = 0;
curloop->e->eflag2 = BME_cycle_length(&curloop->radial);
BME_radial_remove_loop(curloop, curloop->e);
/*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
curloop->radial.next = curloop->radial.prev = NULL;
bm->edar[i] = curloop->e;
}
/*actually reverse the loop. This belongs in BME_cycle_reverse!*/
for(i=0, curloop = l; i < len; i++){
oldnext = curloop->next;
oldprev = curloop->prev;
curloop->next = oldprev;
curloop->prev = oldnext;
curloop = oldnext;
}
if(len == 2){ //two edged face
//do some verification here!
l->e = bm->edar[1];
l->next->e = bm->edar[0];
}
else{
for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
edok = 0;
for(j=0; j < len; j++){
edok = BME_verts_in_edge(curloop->v, curloop->next->v, bm->edar[j]);
if(edok){
curloop->e = bm->edar[j];
break;
}
}
}
}
/*rebuild radial*/
for(i=0, curloop = l; i < len; i++, curloop = curloop->next) BME_radial_append(curloop->e, curloop);
/*validate radial*/
for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial));
if(!edok){
BME_error();
}
}
return 1;
}
/**
* BME_JFKE
*
* JOIN FACE KILL EDGE:
*
* Takes two faces joined by a single 2-manifold edge and fuses them togather.
* The edge shared by the faces must not be connected to any other edges which have
* Both faces in its radial cycle
*
* Examples:
*
* A B
* ---------- ----------
* | | | |
* | f1 | | f1 |
* v1========v2 = Ok! v1==V2==v3 == Wrong!
* | f2 | | f2 |
* | | | |
* ---------- ----------
*
* In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used.
* In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller
* in this case should call BME_JEKV on the extra edges before attempting to fuse f1 and f2.
*
* Also note that the order of arguments decides whether or not certain per-face attributes are present
* in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited
* from f1, not f2.
*
* Returns -
* A BME_Poly pointer
*/
BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
{
BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL;
int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok;
if(f1 == f2) return NULL; //can't join a face to itself
/*verify that e is in both f1 and f2*/
f1len = BME_cycle_length(f1->loopbase);
f2len = BME_cycle_length(f2->loopbase);
for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){
if(curloop->e == e){
f1loop = curloop;
break;
}
}
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){
if(curloop->e==e){
f2loop = curloop;
break;
}
}
if(!(f1loop && f2loop)) return NULL;
/*validate that edge is 2-manifold edge*/
radlen = BME_cycle_length(&(f1loop->radial));
if(radlen != 2) return NULL;
/*validate direction of f2's loop cycle is compatible.*/
if(f1loop->v == f2loop->v) return NULL;
/*
Finally validate that for each face, each vertex has another edge in its disk cycle that is
not e, and not shared.
*/
if(BME_radial_find_face(f1loop->next->e,f2)) return NULL;
if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL;
if(BME_radial_find_face(f2loop->next->e,f1)) return NULL;
if(BME_radial_find_face(f2loop->prev->e,f1)) return NULL;
/*join the two loops*/
f1loop->prev->next = f2loop->next;
f2loop->next->prev = f1loop->prev;
f1loop->next->prev = f2loop->prev;
f2loop->prev->next = f1loop->next;
/*if f1loop was baseloop, give f1loop->next the base.*/
if(f1->loopbase == f1loop) f1->loopbase = f1loop->next;
/*validate the new loop*/
loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase);
if(!loopok) BME_error();
/*make sure each loop points to the proper face*/
newlen = BME_cycle_length(f1->loopbase);
for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1;
f1->len = newlen;
edok = BME_cycle_validate(f1->len, f1->loopbase);
if(!edok) BME_error();
/*remove edge from the disk cycle of its two vertices.*/
BME_disk_remove_edge(f1loop->e, f1loop->e->v1);
BME_disk_remove_edge(f1loop->e, f1loop->e->v2);
/*deallocate edge and its two loops as well as f2*/
BLI_remlink(&(bm->edges), f1loop->e);
BLI_remlink(&(bm->polys), f2);
BME_free_edge(bm, f1loop->e);
BME_free_loop(bm, f1loop);
BME_free_loop(bm, f2loop);
BME_free_poly(bm, f2);
return f1;
}

@ -1,285 +0,0 @@
/*
* BME_mesh.c jan 2007
*
* BMesh mesh level functions.
*
*
* ***** 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.
* about this.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_mesh.c
* \ingroup bke
*/
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
#include "BKE_bmesh.h"
#include "bmesh_private.h"
/*
* BME MAKE MESH
*
* Allocates a new BME_Mesh structure.
* Returns -
* Pointer to a Bmesh
*
*/
BME_Mesh *BME_make_mesh(int allocsize[4])
{
/*allocate the structure*/
BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
/*allocate the memory pools for the mesh elements*/
bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], FALSE, FALSE);
bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], FALSE, FALSE);
bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], FALSE, FALSE);
bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], FALSE, FALSE);
return bm;
}
/*
* BME FREE MESH
*
* Frees a BME_Mesh structure.
*/
void BME_free_mesh(BME_Mesh *bm)
{
BME_Vert *v;
BME_Edge *e;
BME_Loop *l;
BME_Poly *f;
for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data);
for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data);
for(f=bm->polys.first; f; f=f->next){
CustomData_bmesh_free_block(&bm->pdata, &f->data);
l = f->loopbase;
do{
CustomData_bmesh_free_block(&bm->ldata, &l->data);
l = l->next;
}while(l!=f->loopbase);
}
/*Free custom data pools, This should probably go in CustomData_free?*/
if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
/*free custom data*/
CustomData_free(&bm->vdata,0);
CustomData_free(&bm->edata,0);
CustomData_free(&bm->ldata,0);
CustomData_free(&bm->pdata,0);
/*destroy element pools*/
BLI_mempool_destroy(bm->vpool);
BLI_mempool_destroy(bm->epool);
BLI_mempool_destroy(bm->ppool);
BLI_mempool_destroy(bm->lpool);
MEM_freeN(bm);
}
/*
* BME MODEL BEGIN AND END
*
* These two functions represent the 'point of entry' for tools. Every BMesh tool
* must begin with a call to BME_model_end() and finish with a call to BME_model_end().
* No modification of mesh data is allowed except in between these two calls.
*
* The purpose of these calls is allow for housekeeping tasks to be performed,
* such as allocating/freeing scratch arrays or performing debug validation of
* the mesh structure.
*
* Returns -
* Nothing
*
*/
int BME_model_begin(BME_Mesh *bm){
/*Initialize some scratch pointer arrays used by eulers*/
bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array");
bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array");
bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array");
bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array");
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
return 1;
}
void BME_model_end(BME_Mesh *bm){
int meshok, totvert, totedge, totpoly;
totvert = BLI_countlist(&(bm->verts));
totedge = BLI_countlist(&(bm->edges));
totpoly = BLI_countlist(&(bm->polys));
if(bm->vtar) MEM_freeN(bm->vtar);
if(bm->edar) MEM_freeN(bm->edar);
if(bm->lpar) MEM_freeN(bm->lpar);
if(bm->plar) MEM_freeN(bm->plar);
bm->vtar = NULL;
bm->edar = NULL;
bm->lpar = NULL;
bm->plar = NULL;
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly)
BME_error();
meshok = BME_validate_mesh(bm, 1);
if(!meshok){
BME_error();
}
}
/*
* BME VALIDATE MESH
*
* There are several levels of validation for meshes. At the
* Euler level, some basic validation is done to local topology.
* To catch more subtle problems however, BME_validate_mesh() is
* called by BME_model_end() whenever a tool is done executing.
* The purpose of this function is to insure that during the course
* of tool execution that nothing has been done to invalidate the
* structure, and if it has, provide a way of reporting that so that
* we can restore the proper structure from a backup. Since a full mesh
* validation would be too expensive, this is presented as a compromise.
*
* TODO
*
* -Make this only part of debug builds
*/
#define VHALT(halt) {BME_error(); if(halt) return 0;}
int BME_validate_mesh(struct BME_Mesh *bm, int halt)
{
BME_Vert *v;
BME_Edge *e;
BME_Poly *f;
BME_Loop *l;
BME_CycleNode *diskbase;
int i, ok;
/*Simple edge verification*/
for(e=bm->edges.first; e; e=e->next){
if(e->v1 == e->v2) VHALT(halt);
/*validate e->d1.data and e->d2.data*/
if(e->d1.data != e || e->d2.data != e) VHALT(halt);
/*validate e->loop->e*/
if(e->loop){
if(e->loop->e != e) VHALT(halt);
}
}
/*calculate disk cycle lengths*/
for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0;
for(e=bm->edges.first; e; e=e->next){
e->v1->tflag1++;
e->v2->tflag1++;
}
/*Validate vertices and disk cycle*/
for(v=bm->verts.first; v; v=v->next){
/*validate v->edge pointer*/
if(v->tflag1){
if(v->edge){
ok = BME_vert_in_edge(v->edge,v);
if(!ok) VHALT(halt);
/*validate length of disk cycle*/
diskbase = BME_disk_getpointer(v->edge, v);
ok = BME_cycle_validate(v->tflag1, diskbase);
if(!ok) VHALT(halt);
/*validate that each edge in disk cycle contains V*/
for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
ok = BME_vert_in_edge(e, v);
if(!ok) VHALT(halt);
}
}
else VHALT(halt);
}
}
/*validate edges*/
for(e=bm->edges.first; e; e=e->next){
/*seperate these into BME_disk_hasedge (takes pointer to edge)*/
/*search v1 disk cycle for edge*/
ok = BME_disk_hasedge(e->v1,e);
if(!ok) VHALT(halt);
/*search v2 disk cycle for edge*/
ok = BME_disk_hasedge(e->v2,e);
if(!ok) VHALT(halt);
}
for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces
/*Validate the loop cycle integrity.*/
for(f=bm->polys.first; f; f=f->next){
ok = BME_cycle_length(f->loopbase);
if(ok > 1){
f->tflag1 = ok;
}
else VHALT(halt);
for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){
/*verify loop->v pointers*/
ok = BME_verts_in_edge(l->v, l->next->v, l->e);
if(!ok) VHALT(halt);
/*verify radial node data pointer*/
if(l->radial.data != l) VHALT(halt);
/*validate l->e->loop poitner*/
if(l->e->loop == NULL) VHALT(halt);
/*validate l->f pointer*/
if(l->f != f) VHALT(halt);
/*see if l->e->loop is actually in radial cycle*/
l->e->tflag2++;
}
}
/*validate length of radial cycle*/
for(e=bm->edges.first; e; e=e->next){
if(e->loop){
ok = BME_cycle_validate(e->tflag2,&(e->loop->radial));
if(!ok) VHALT(halt);
}
}
/*validate that EIDs are within range... if not indicates corrupted mem*/
/*if we get this far, pretty safe to return 1*/
return 1;
}
/* Currently just a convient place for a breakpoint.
Probably should take an error string
*/
void BME_error(void){
printf("BME modelling error!");
}

@ -1,628 +0,0 @@
/*
* BME_structure.c jan 2007
*
* Low level routines for manipulating the BMesh structure.
*
*
* ***** 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.
* about this.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_structure.c
* \ingroup bke
*/
#include <limits.h>
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_bmesh.h"
/**
* MISC utility functions.
*
*/
int BME_vert_in_edge(BME_Edge *e, BME_Vert *v){
if(e->v1 == v || e->v2 == v) return 1;
return 0;
}
int BME_verts_in_edge(BME_Vert *v1, BME_Vert *v2, BME_Edge *e){
if(e->v1 == v1 && e->v2 == v2) return 1;
else if(e->v1 == v2 && e->v2 == v1) return 1;
return 0;
}
BME_Vert *BME_edge_getothervert(BME_Edge *e, BME_Vert *v){
if(e->v1 == v) return e->v2;
else if(e->v2 == v) return e->v1;
return NULL;
}
int BME_edge_swapverts(BME_Edge *e, BME_Vert *orig, BME_Vert *new){
if(e->v1 == orig){
e->v1 = new;
e->d1.next = NULL;
e->d1.prev = NULL;
return 1;
}
else if(e->v2 == orig){
e->v2 = new;
e->d2.next = NULL;
e->d2.prev = NULL;
return 1;
}
return 0;
}
/**
* ALLOCATION/DEALLOCATION FUNCTIONS
*/
BME_Vert *BME_addvertlist(BME_Mesh *bm, BME_Vert *example){
BME_Vert *v=NULL;
v = BLI_mempool_alloc(bm->vpool);
v->next = v->prev = NULL;
v->EID = bm->nextv;
v->co[0] = v->co[1] = v->co[2] = 0.0f;
v->no[0] = v->no[1] = v->no[2] = 0.0f;
v->edge = NULL;
v->data = NULL;
v->eflag1 = v->eflag2 = v->tflag1 = v->tflag2 = 0;
v->flag = v->h = 0;
v->bweight = 0.0f;
BLI_addtail(&(bm->verts), v);
bm->nextv++;
bm->totvert++;
if(example){
VECCOPY(v->co,example->co);
CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data);
}
else
CustomData_bmesh_set_default(&bm->vdata, &v->data);
return v;
}
BME_Edge *BME_addedgelist(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge *example){
BME_Edge *e=NULL;
e = BLI_mempool_alloc(bm->epool);
e->next = e->prev = NULL;
e->EID = bm->nexte;
e->v1 = v1;
e->v2 = v2;
e->d1.next = e->d1.prev = e->d2.next = e->d2.prev = NULL;
e->d1.data = e;
e->d2.data = e;
e->loop = NULL;
e->data = NULL;
e->eflag1 = e->eflag2 = e->tflag1 = e->tflag2 = 0;
e->flag = e->h = 0;
e->crease = e->bweight = 0.0f;
bm->nexte++;
bm->totedge++;
BLI_addtail(&(bm->edges), e);
if(example)
CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->data, &e->data);
else
CustomData_bmesh_set_default(&bm->edata, &e->data);
return e;
}
BME_Loop *BME_create_loop(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Poly *f, BME_Loop *example){
BME_Loop *l=NULL;
l = BLI_mempool_alloc(bm->lpool);
l->next = l->prev = NULL;
l->EID = bm->nextl;
l->radial.next = l->radial.prev = NULL;
l->radial.data = l;
l->v = v;
l->e = e;
l->f = f;
l->data = NULL;
l->eflag1 = l->eflag2 = l->tflag1 = l->tflag2 = 0;
l->flag = l->h = 0; //stupid waste!
bm->nextl++;
bm->totloop++;
if(example)
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->data, &l->data);
else
CustomData_bmesh_set_default(&bm->ldata, &l->data);
return l;
}
BME_Poly *BME_addpolylist(BME_Mesh *bm, BME_Poly *example){
BME_Poly *f = NULL;
f = BLI_mempool_alloc(bm->ppool);
f->next = f->prev = NULL;
f->EID = bm->nextp;
f->loopbase = NULL;
f->len = 0;
f->data = NULL;
f->eflag1 = f->eflag2 = f->tflag1 = f->tflag2 = 0;
f->flag = f->h = f->mat_nr;
BLI_addtail(&(bm->polys),f);
bm->nextp++;
bm->totpoly++;
if(example)
CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data);
else
CustomData_bmesh_set_default(&bm->pdata, &f->data);
return f;
}
/* free functions dont do much *yet*. When per-vertex, per-edge and per-face/faceloop
data is added though these will be needed.
*/
void BME_free_vert(BME_Mesh *bm, BME_Vert *v){
bm->totvert--;
CustomData_bmesh_free_block(&bm->vdata, &v->data);
BLI_mempool_free(bm->vpool, v);
}
void BME_free_edge(BME_Mesh *bm, BME_Edge *e){
bm->totedge--;
CustomData_bmesh_free_block(&bm->edata, &e->data);
BLI_mempool_free(bm->epool, e);
}
void BME_free_poly(BME_Mesh *bm, BME_Poly *f){
bm->totpoly--;
CustomData_bmesh_free_block(&bm->pdata, &f->data);
BLI_mempool_free(bm->ppool, f);
}
void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
bm->totloop--;
CustomData_bmesh_free_block(&bm->ldata, &l->data);
BLI_mempool_free(bm->lpool, l);
}
/**
* BMESH CYCLES
*
* Cycles are circular doubly linked lists that form the basis of adjacency
* information in the BME modeller. Full adjacency relations can be derived
* from examining these cycles very quickly. Although each cycle is a double
* circular linked list, each one is considered to have a 'base' or 'head',
* and care must be taken by Euler code when modifying the contents of a cycle.
*
* The contents of this file are split into two parts. First there are the
* BME_cycle family of functions which are generic circular double linked list
* procedures. The second part contains higher level procedures for supporting
* modification of specific cycle types.
*
* The three cycles explicitly stored in the BMesh data structure are as follows:
*
* 1: The Disk Cycle - A circle of edges around a vertex
* Base: vertex->edge pointer.
*
* This cycle is the most complicated in terms of its structure. Each BME_Edge contains
* two BME_CycleNode structures to keep track of that edge's membership in the disk cycle
* of each of its vertices. However for any given vertex it may be the first in some edges
* in its disk cycle and the second for others. The BME_disk_XXX family of functions contain
* some nice utilities for navigating disk cycles in a way that hides this detail from the
* tool writer.
*
* Note that the disk cycle is completley independant from face data. One advantage of this
* is that wire edges are fully integrated into the topology database. Another is that the
* the disk cycle has no problems dealing with non-manifold conditions involving faces.
*
* Functions relating to this cycle:
*
* BME_disk_append_edge
* BME_disk_remove_edge
* BME_disk_nextedge
* BME_disk_getpointer
*
* 2: The Radial Cycle - A circle of face edges (BME_Loop) around an edge
* Base: edge->loop->radial structure.
*
* The radial cycle is similar to the radial cycle in the radial edge data structure.*
* Unlike the radial edge however, the radial cycle does not require a large amount of memory
* to store non-manifold conditions since BMesh does not keep track of region/shell
* information.
*
* Functions relating to this cycle:
*
* BME_radial_append
* BME_radial_remove_loop
* BME_radial_nextloop
* BME_radial_find_face
*
*
* 3: The Loop Cycle - A circle of face edges around a polygon.
* Base: polygon->loopbase.
*
* The loop cycle keeps track of a faces vertices and edges. It should be noted that the
* direction of a loop cycle is either CW or CCW depending on the face normal, and is
* not oriented to the faces editedges.
*
* Functions relating to this cycle:
*
* BME_cycle_XXX family of functions.
*
*
* Note that the order of elements in all cycles except the loop cycle is undefined. This
* leads to slightly increased seek time for deriving some adjacency relations, however the
* advantage is that no intrinsic properties of the data structures are dependant upon the
* cycle order and all non-manifold conditions are represented trivially.
*
*/
void BME_cycle_append(void *h, void *nt)
{
BME_CycleNode *oldtail, *head, *newtail;
head = (BME_CycleNode*)h;
newtail = (BME_CycleNode*)nt;
if(head->next == NULL){
head->next = newtail;
head->prev = newtail;
newtail->next = head;
newtail->prev = head;
}
else{
oldtail = head->prev;
oldtail->next = newtail;
newtail->next = head;
newtail->prev = oldtail;
head->prev = newtail;
}
}
/**
* BME_cycle_length
*
* Count the nodes in a cycle.
*
* Returns -
* Integer
*/
int BME_cycle_length(void *h){
int len = 0;
BME_CycleNode *head, *curnode;
head = (BME_CycleNode*)h;
if(head){
len = 1;
for(curnode = head->next; curnode != head; curnode=curnode->next){
if(len == INT_MAX){ //check for infinite loop/corrupted cycle
return -1;
}
len++;
}
}
return len;
}
/**
* BME_cycle_remove
*
* Removes a node from a cycle.
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_cycle_remove(void *h, void *remn)
{
int i, len;
BME_CycleNode *head, *remnode, *curnode;
head = (BME_CycleNode*)h;
remnode = (BME_CycleNode*)remn;
len = BME_cycle_length(h);
if(len == 1 && head == remnode){
head->next = NULL;
head->prev = NULL;
return 1;
}
else{
for(i=0, curnode = head; i < len; curnode = curnode->next){
if(curnode == remnode){
remnode->prev->next = remnode->next;
remnode->next->prev = remnode->prev;
/*zero out remnode pointers, important!*/
//remnode->next = NULL;
//remnode->prev = NULL;
return 1;
}
}
}
return 0;
}
/**
* BME_cycle_validate
*
* Validates a cycle. Takes as an argument the expected length of the cycle and
* a pointer to the cycle head or base.
*
*
* Returns -
* 1 for success, 0 for failure.
*/
int BME_cycle_validate(int len, void *h){
int i;
BME_CycleNode *curnode, *head;
head = (BME_CycleNode*)h;
/*forward validation*/
for(i = 0, curnode = head; i < len; i++, curnode = curnode->next);
if(curnode != head) return 0;
/*reverse validation*/
for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev);
if(curnode != head) return 0;
return 1;
}
/*Begin Disk Cycle routines*/
/**
* BME_disk_nextedge
*
* Find the next edge in a disk cycle
*
* Returns -
* Pointer to the next edge in the disk cycle for the vertex v.
*/
BME_Edge *BME_disk_nextedge(BME_Edge *e, BME_Vert *v)
{
if(BME_vert_in_edge(e, v)){
if(e->v1 == v) return e->d1.next->data;
else if(e->v2 == v) return e->d2.next->data;
}
return NULL;
}
/**
* BME_disk_getpointer
*
* Given an edge and one of its vertices, find the apporpriate CycleNode
*
* Returns -
* Pointer to BME_CycleNode.
*/
BME_CycleNode *BME_disk_getpointer(BME_Edge *e, BME_Vert *v){
/*returns pointer to the cycle node for the appropriate vertex in this disk*/
if(e->v1 == v) return &(e->d1);
else if (e->v2 == v) return &(e->d2);
return NULL;
}
/**
* BME_disk_append_edge
*
* Appends edge to the end of a vertex disk cycle.
*
* Returns -
* 1 for success, 0 for failure
*/
int BME_disk_append_edge(BME_Edge *e, BME_Vert *v)
{
BME_CycleNode *base, *tail;
if(BME_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/
/*check for loose vert first*/
if(v->edge == NULL){
v->edge = e;
base = tail = BME_disk_getpointer(e, v);
BME_cycle_append(base, tail); /*circular reference is ok!*/
return 1;
}
/*insert e at the end of disk cycle and make it the new v->edge*/
base = BME_disk_getpointer(v->edge, v);
tail = BME_disk_getpointer(e, v);
BME_cycle_append(base, tail);
return 1;
}
/**
* BME_disk_remove_edge
*
* Removes an edge from a disk cycle. If the edge to be removed is
* at the base of the cycle, the next edge becomes the new base.
*
*
* Returns -
* Nothing
*/
void BME_disk_remove_edge(BME_Edge *e, BME_Vert *v)
{
BME_CycleNode *base, *remnode;
BME_Edge *newbase;
int len;
base = BME_disk_getpointer(v->edge, v);
remnode = BME_disk_getpointer(e, v);
/*first deal with v->edge pointer...*/
len = BME_cycle_length(base);
if(len == 1) newbase = NULL;
else if(v->edge == e) newbase = base->next-> data;
else newbase = v->edge;
/*remove and rebase*/
BME_cycle_remove(base, remnode);
v->edge = newbase;
}
/**
* BME_disk_next_edgeflag
*
* Searches the disk cycle of v, starting with e, for the
* next edge that has either eflag or tflag.
*
* BME_Edge pointer.
*/
BME_Edge *BME_disk_next_edgeflag(BME_Edge *e, BME_Vert *v, int eflag, int tflag){
/* BME_CycleNode *diskbase; */ /* UNUSED */
BME_Edge *curedge;
int /* len, */ /* UNUSED */ ok;
if(eflag && tflag) return NULL;
ok = BME_vert_in_edge(e,v);
if(ok){
/* diskbase = BME_disk_getpointer(e, v); */ /* UNUSED */
/* len = BME_cycle_length(diskbase); */ /* UNUSED */
curedge = BME_disk_nextedge(e,v);
while(curedge != e){
if(tflag){
if(curedge->tflag1 == tflag) return curedge;
}
else if(eflag){
if(curedge->eflag1 == eflag) return curedge;
}
curedge = BME_disk_nextedge(curedge, v);
}
}
return NULL;
}
/**
* BME_disk_count_edgeflag
*
* Counts number of edges in this verts disk cycle which have
* either eflag or tflag (but not both!)
*
* Returns -
* Integer.
*/
int BME_disk_count_edgeflag(BME_Vert *v, int eflag, int tflag){
BME_CycleNode *diskbase;
BME_Edge *curedge;
int i, len=0, count=0;
if(v->edge){
if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
diskbase = BME_disk_getpointer(v->edge, v);
len = BME_cycle_length(diskbase);
for(i = 0, curedge=v->edge; i<len; i++){
if(tflag){
if(curedge->tflag1 == tflag) count++;
}
else if(eflag){
if(curedge->eflag1 == eflag) count++;
}
curedge = BME_disk_nextedge(curedge, v);
}
}
return count;
}
int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){
BME_CycleNode *diskbase;
BME_Edge *curedge;
int i, len=0;
if(v->edge){
diskbase = BME_disk_getpointer(v->edge,v);
len = BME_cycle_length(diskbase);
for(i = 0, curedge=v->edge; i<len; i++){
if(curedge == e) return 1;
else curedge=BME_disk_nextedge(curedge, v);
}
}
return 0;
}
/*end disk cycle routines*/
BME_Loop *BME_radial_nextloop(BME_Loop *l){
return (BME_Loop*)(l->radial.next->data);
}
void BME_radial_append(BME_Edge *e, BME_Loop *l){
if(e->loop == NULL) e->loop = l;
BME_cycle_append(&(e->loop->radial), &(l->radial));
}
void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e)
{
BME_Loop *newbase;
int len;
/*deal with edge->loop pointer*/
len = BME_cycle_length(&(e->loop->radial));
if(len == 1) newbase = NULL;
else if(e->loop == l) newbase = e->loop->radial.next->data;
else newbase = e->loop;
/*remove and rebase*/
BME_cycle_remove(&(e->loop->radial), &(l->radial));
e->loop = newbase;
}
int BME_radial_find_face(BME_Edge *e,BME_Poly *f)
{
BME_Loop *curloop;
int i, len;
len = BME_cycle_length(&(e->loop->radial));
for(i = 0, curloop = e->loop; i < len; i++, curloop = curloop->radial.next->data){
if(curloop->f == f) return 1;
}
return 0;
}
struct BME_Loop *BME_loop_find_loop(struct BME_Poly *f, struct BME_Vert *v) {
BME_Loop *l;
int i, len;
len = BME_cycle_length(f->loopbase);
for (i = 0, l=f->loopbase; i < len; i++, l=l->next) {
if (l->v == v) return l;
}
return NULL;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -65,6 +65,7 @@
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_utildefines.h"
#include "BKE_tessmesh.h"
#include "BKE_depsgraph.h"
#include "BKE_anim.h"
#include "BKE_report.h"
@ -898,7 +899,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
Scene *sce = NULL;
Group *group = NULL;
GroupObject * go = NULL;
EditMesh *em;
BMEditMesh *em;
float vec[3], no[3], pmat[4][4];
int totvert, a, oblay;
unsigned int lay;
@ -908,11 +909,10 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
/* simple preventing of too deep nested groups */
if(level>MAX_DUPLI_RECUR) return;
em = BKE_mesh_get_editmesh(me);
em = me->edit_btmesh;
if(em) {
dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
BKE_mesh_end_editmesh(me, em);
dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
} else
dm= mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
@ -974,7 +974,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
/* mballs have a different dupli handling */
if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
if(me->edit_mesh) {
if(me->edit_btmesh) {
dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd);
}
else {
@ -1015,44 +1015,45 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
DupliObject *dob;
DerivedMesh *dm;
Mesh *me= par->data;
MTFace *mtface;
MFace *mface;
MLoopUV *mloopuv;
MPoly *mpoly, *mp;
MLoop *mloop;
MVert *mvert;
float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
int lay, oblay, totface, a;
Scene *sce = NULL;
Group *group = NULL;
GroupObject *go = NULL;
EditMesh *em;
BMEditMesh *em;
float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
/* simple preventing of too deep nested groups */
if(level>MAX_DUPLI_RECUR) return;
copy_m4_m4(pmat, par->obmat);
em = BKE_mesh_get_editmesh(me);
em = me->edit_btmesh;
if(em) {
dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
BKE_mesh_end_editmesh(me, em);
dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
}
else {
dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
}
totface= dm->getNumFaces(dm);
mface= dm->getFaceArray(dm);
totface= dm->getNumPolys(dm);
mpoly= dm->getPolyArray(dm);
mloop= dm->getLoopArray(dm);
mvert= dm->getVertArray(dm);
if(G.rendering) {
orco= (float(*)[3])get_mesh_orco_verts(par);
transform_mesh_orco_verts(me, orco, me->totvert, 0);
mtface= me->mtface;
mloopuv= me->mloopuv;
}
else {
orco= NULL;
mtface= NULL;
mloopuv= NULL;
}
/* having to loop on scene OR group objects is NOT FUN */
@ -1096,22 +1097,36 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
/* mballs have a different dupli handling */
if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
for(a=0; a<totface; a++) {
int mv1 = mface[a].v1;
int mv2 = mface[a].v2;
int mv3 = mface[a].v3;
int mv4 = mface[a].v4;
float *v1= mvert[mv1].co;
float *v2= mvert[mv2].co;
float *v3= mvert[mv3].co;
float *v4= (mv4)? mvert[mv4].co: NULL;
for(a=0, mp= mpoly; a<totface; a++, mp++) {
int mv1;
int mv2;
int mv3;
/* int mv4; */ /* UNUSED */
float *v1;
float *v2;
float *v3;
/* float *v4; */ /* UNUSED */
float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
MLoop *loopstart= mloop + mp->loopstart;
if (mp->totloop < 3) {
/* highly unlikely but to be safe */
continue;
}
else {
v1= mvert[(mv1= loopstart[0].v)].co;
v2= mvert[(mv2= loopstart[1].v)].co;
v3= mvert[(mv3= loopstart[2].v)].co;
/*
if (mp->totloop > 3) {
v4= mvert[(mv4= loopstart[3].v)].co;
}
*/
}
/* translation */
if(v4)
cent_quad_v3(cent, v1, v2, v3, v4);
else
cent_tri_v3(cent, v1, v2, v3);
mesh_calc_poly_center(mp, loopstart, mvert, cent);
mul_m4_v3(pmat, cent);
sub_v3_v3v3(cent, cent, pmat[3]);
@ -1127,7 +1142,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
/* scale */
if(par->transflag & OB_DUPLIFACES_SCALE) {
float size= v4? area_quad_v3(v1, v2, v3, v4): area_tri_v3(v1, v2, v3);
float size= mesh_calc_poly_area(mp, loopstart, mvert, NULL);
size= sqrtf(size) * par->dupfacesca;
mul_m3_fl(mat, size);
}
@ -1140,23 +1155,19 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
dob= new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated);
if(G.rendering) {
w= (mv4)? 0.25f: 1.0f/3.0f;
w= 1.0f / (float)mp->totloop;
if(orco) {
madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv1], w);
madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv2], w);
madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv3], w);
if (mv4) {
madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv4], w);
int j;
for (j = 0; j < mpoly->totloop; j++) {
madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
}
}
if(mtface) {
madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[0], w);
madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[1], w);
madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[2], w);
if (mv4) {
madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[3], w);
if(mloopuv) {
int j;
for (j = 0; j < mpoly->totloop; j++) {
madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
}
}
}

@ -1302,6 +1302,17 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm
mul_v3_m4v3(outmat[3], loc_mat, inmat[3]);
}
/* Convert Bone-Space Matrix to Pose-Space Matrix. */
void armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[][4], float outmat[][4])
{
float rotscale_mat[4][4], loc_mat[4][4];
pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
mult_m4_m4m4(outmat, rotscale_mat, inmat);
mul_v3_m4v3(outmat[3], loc_mat, inmat[3]);
}
/* Convert Pose-Space Location to Bone-Space Location
* NOTE: this cannot be used to convert to pose-space location of the supplied
* pose-channel into its local space (i.e. 'visual'-keyframing)
@ -2405,6 +2416,8 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
/* Construct the posemat based on PoseChannels, that we do before applying constraints. */
/* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
armature_mat_bone_to_pose(pchan, pchan->chan_mat, pchan->pose_mat);
#if 0 /* XXX Old code, will remove this later. */
{
float rotscale_mat[4][4], loc_mat[4][4];
pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
@ -2413,6 +2426,7 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
/* Location. */
mul_v3_m4v3(pchan->pose_mat[3], loc_mat, pchan->chan_mat[3]);
}
#endif
/* Only rootbones get the cyclic offset (unless user doesn't want that). */
/* XXX That could be a problem for snapping and other "reverse transform" features... */

@ -41,7 +41,7 @@
#include "BLI_linklist.h"
#include "BKE_DerivedMesh.h"
#include "BKE_tessmesh.h"
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
@ -555,7 +555,7 @@ BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float
data->mesh = mesh;
data->vert = mesh->getVertDataArray(mesh, CD_MVERT);
data->face = mesh->getFaceDataArray(mesh, CD_MFACE);
data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
data->sphere_radius = epsilon;
}
@ -572,22 +572,87 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
if(tree == NULL)
{
int i;
int numFaces= mesh->getNumFaces(mesh);
MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE);
int numFaces= mesh->getNumTessFaces(mesh);
if(vert != NULL && face != NULL)
/* BMESH spesific check that we have tessfaces,
* we _could_ tesselate here but rather not - campbell
*
* this assert checks we have tessfaces,
* if not caller should use DM_ensure_tessface() */
BLI_assert(!(numFaces == 0 && mesh->getNumPolys(mesh) != 0));
if(numFaces != 0)
{
/* Create a bvh-tree of the given target */
tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis);
if(tree != NULL)
{
/* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */
EditMesh *em= data->em_evil;
BMEditMesh *em= data->em_evil;
if(em) {
EditFace *efa= em->faces.first;
for(i = 0; i < numFaces; i++, efa= efa->next) {
if(!(efa->f & 1) && efa->h==0 && !((efa->v1->f&1)+(efa->v2->f&1)+(efa->v3->f&1)+(efa->v4?efa->v4->f&1:0))) {
/*data->em_evil is only set for snapping, and only for the mesh of the object
which is currently open in edit mode. When set, the bvhtree should not contain
faces that will interfere with snapping (e.g. faces that are hidden/selected
or faces that have selected verts).*/
/* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */
/*Insert BMesh-tesselation triangles into the bvh tree, unless they are hidden
and/or selected. Even if the faces themselves are not selected for the snapped
transform, having a vertex selected means the face (and thus it's tesselated
triangles) will be moving and will not be a good snap targets.*/
for (i = 0; i < em->tottri; i++) {
BMLoop **tri = em->looptris[i];
BMFace *f;
BMVert *v;
BMIter iter;
int insert;
/*Each loop of the triangle points back to the BMFace it was tesselated from.
All three should point to the same face, so just use the face from the first
loop.*/
f = tri[0]->f;
/*If the looptris is ordered such that all triangles tesselated from a single
faces are consecutive elements in the array, then we could speed up the tests
below by using the insert value from the previous iteration.*/
/*Start with the assumption the triangle should be included for snapping.*/
insert = 1;
if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
/*Don't insert triangles tesselated from faces that are hidden
or selected*/
insert = 0;
}
else {
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_FACE, f) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
/*Don't insert triangles tesselated from faces that have
any selected verts.*/
insert = 0;
}
}
}
if (insert)
{
/*No reason found to block hit-testing the triangle for snap,
so insert it now.*/
float co[4][3];
copy_v3_v3(co[0], tri[0]->v->co);
copy_v3_v3(co[1], tri[1]->v->co);
copy_v3_v3(co[2], tri[2]->v->co);
BLI_bvhtree_insert(tree, i, co[0], 3);
}
}
}
else {
MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
MFace *face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
if (vert != NULL && face != NULL) {
for(i = 0; i < numFaces; i++) {
float co[4][3];
copy_v3_v3(co[0], vert[ face[i].v1 ].co);
copy_v3_v3(co[1], vert[ face[i].v2 ].co);
@ -599,18 +664,6 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
}
}
}
else {
for(i = 0; i < numFaces; i++) {
float co[4][3];
copy_v3_v3(co[0], vert[ face[i].v1 ].co);
copy_v3_v3(co[1], vert[ face[i].v2 ].co);
copy_v3_v3(co[2], vert[ face[i].v3 ].co);
if(face[i].v4)
copy_v3_v3(co[3], vert[ face[i].v4 ].co);
BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
}
}
BLI_bvhtree_balance(tree);
//Save on cache for later use
@ -638,7 +691,7 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
data->mesh = mesh;
data->vert = mesh->getVertDataArray(mesh, CD_MVERT);
data->face = mesh->getFaceDataArray(mesh, CD_MFACE);
data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
data->sphere_radius = epsilon;
}

File diff suppressed because it is too large Load Diff

@ -35,6 +35,7 @@
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
@ -930,8 +931,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
{
unsigned int numverts = dm->getNumVerts ( dm );
unsigned int numfaces = dm->getNumFaces ( dm );
MFace *mface = dm->getFaceArray( dm );
unsigned int numfaces = dm->getNumTessFaces ( dm );
MFace *mface = dm->getTessFaceArray( dm );
unsigned int i = 0;
/* Allocate our vertices. */
@ -1043,9 +1044,9 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
unsigned int i = 0;
unsigned int numverts = (unsigned int)dm->getNumVerts ( dm );
unsigned int numedges = (unsigned int)dm->getNumEdges ( dm );
unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm );
unsigned int numfaces = (unsigned int)dm->getNumTessFaces ( dm );
MEdge *medge = dm->getEdgeArray ( dm );
MFace *mface = dm->getFaceArray ( dm );
MFace *mface = dm->getTessFaceArray ( dm );
int index2 = 0; // our second vertex index
LinkNode **edgelist = NULL;
EdgeHash *edgehash = NULL;

@ -42,6 +42,7 @@
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"

@ -77,8 +77,12 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_idprop.h"
#include "BKE_mesh.h"
#include "BKE_shrinkwrap.h"
#include "BKE_mesh.h"
#include "BKE_tessmesh.h"
#include "BKE_tracking.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "BKE_movieclip.h"
@ -421,7 +425,7 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
{
DerivedMesh *dm = NULL;
Mesh *me= ob->data;
EditMesh *em = BKE_mesh_get_editmesh(me);
BMEditMesh *em = me->edit_btmesh;
float vec[3] = {0.0f, 0.0f, 0.0f};
float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3];
float imat[3][3], tmat[3][3];
@ -437,7 +441,7 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
/* get DerivedMesh */
if (em) {
/* target is in editmode, so get a special derived mesh */
dm = CDDM_from_editmesh(em, ob->data);
dm = CDDM_from_BMEditMesh(em, ob->data, FALSE, FALSE);
freeDM= 1;
}
else {
@ -511,8 +515,6 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
/* free temporary DerivedMesh created (in EditMode case) */
if (dm && freeDM)
dm->release(dm);
if (em)
BKE_mesh_end_editmesh(me, em);
}
/* function that sets the given matrix based on given vertex group in lattice */

@ -44,6 +44,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
@ -54,9 +55,13 @@
#include "BKE_customdata_file.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_utildefines.h"
#include "BKE_multires.h"
#include "bmesh.h"
#include <math.h>
#include <string.h>
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@ -440,6 +445,23 @@ static void layerSwap_mdisps(void *data, const int *ci)
}
}
#if 1 /* BMESH_TODO: place holder function, dont actually interp */
static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
float *UNUSED(sub_weights), int UNUSED(count), void *dest)
{
MDisps *d = dest;
/* happens when flipping normals of newly created mesh */
if(!d->totdisp) {
d->totdisp = ((MDisps*)sources[0])->totdisp;
}
if (!d->disps && d->totdisp)
d->disps = MEM_callocN(sizeof(float)*3*d->totdisp, "blank mdisps in layerInterp_mdisps");
}
#else // BMESH_TODO
static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
float *sub_weights, int count, void *dest)
{
@ -552,6 +574,7 @@ static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
MEM_freeN(d->disps);
d->disps = disps;
}
#endif // BMESH_TODO
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
@ -574,6 +597,10 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
static void layerValidate_mdisps(void *data, int sub_elements)
{
#if 1 /*BMESH_TODO*/
(void)data;
(void)sub_elements;
#else
MDisps *disps = data;
if(disps->disps) {
int corners = multires_mdisp_corners(disps);
@ -584,6 +611,7 @@ static void layerValidate_mdisps(void *data, int sub_elements)
disps->disps = MEM_callocN(3*disps->totdisp*sizeof(float), "layerValidate_mdisps");
}
}
#endif
}
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
@ -843,6 +871,77 @@ static void layerInterp_mloopuv(void **sources, float *weights,
}
}
/* origspace is almost exact copy of mloopuv's, keep in sync */
static void layerCopyValue_mloop_origspace(void *source, void *dest)
{
OrigSpaceLoop *luv1 = source, *luv2 = dest;
copy_v2_v2(luv2->uv, luv1->uv);
}
static int layerEqual_mloop_origspace(void *data1, void *data2)
{
OrigSpaceLoop *luv1 = data1, *luv2 = data2;
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloop_origspace(void *data, float fac)
{
OrigSpaceLoop *luv = data;
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
{
OrigSpaceLoop *min = vmin, *max = vmax;
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloop_origspace(void *data, void *vmin, void *vmax)
{
OrigSpaceLoop *min = vmin, *max = vmax, *luv = data;
DO_MINMAX2(luv->uv, min->uv, max->uv);
}
static void layerAdd_mloop_origspace(void *data1, void *data2)
{
OrigSpaceLoop *l1 = data1, *l2 = data2;
add_v2_v2(l1->uv, l2->uv);
}
static void layerInterp_mloop_origspace(void **sources, float *weights,
float *sub_weights, int count, void *dest)
{
OrigSpaceLoop *mluv = dest;
float *uv= mluv->uv;
int i;
zero_v2(uv);
if (sub_weights) {
const float *sub_weight = sub_weights;
for(i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1.0f;
OrigSpaceLoop *src = sources[i];
madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight);
sub_weight++;
}
}
else {
for(i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
OrigSpaceLoop *src = sources[i];
madd_v2_v2fl(uv, src->uv, weight);
}
}
}
/* --- end copy */
static void layerInterp_mcol(void **sources, float *weights,
float *sub_weights, int count, void *dest)
{
@ -992,7 +1091,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(float)*3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 9: CD_POLYINDEX */
{sizeof(int), "MIntProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 10: CD_PROP_FLT */
@ -1037,9 +1136,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 24: CD_RECAST */
{sizeof(MRecast), "MRecast", 1,"Recast",NULL,NULL,NULL,NULL}
#ifdef USE_BMESH_FORWARD_COMPAT
,
/* BMESH ONLY */
,
/* 25: CD_MPOLY */
{sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL},
/* 26: CD_MLOOP */
@ -1052,16 +1150,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float), "", 0, "BevelWeight", NULL, NULL, layerInterp_bweight},
/* 30: CD_CREASE */
{sizeof(float), "", 0, "SubSurfCrease", NULL, NULL, layerInterp_bweight},
/* 31: CD_WEIGHT_MLOOPCOL */
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop), "OrigSpaceLoop", 1, "OS Loop", NULL, NULL, layerInterp_mloop_origspace, NULL, NULL,
layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace,
layerAdd_mloop_origspace, layerDoMinMax_mloop_origspace, layerCopyValue_mloop_origspace},
/* 32: CD_WEIGHT_MLOOPCOL */
{sizeof(MLoopCol), "MLoopCol", 1, "WeightLoopCol", NULL, NULL, layerInterp_mloopcol, NULL,
layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
/* END BMESH ONLY */
#endif /* USE_BMESH_FORWARD_COMPAT */
};
/* note, numbers are from trunk and need updating for bmesh */
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
/* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
@ -1069,29 +1172,38 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-24 */"CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast"
#ifdef USE_BMESH_FORWARD_COMPAT
/* BMESH ONLY */
,
/* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight",
/* 30-31 */ "CDSubSurfCrease", "CDWeightLoopCol"
/* 30-32 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDWeightLoopCol"
/* END BMESH ONLY */
#endif /* USE_BMESH_FORWARD_COMPAT */
};
const CustomDataMask CD_MASK_BAREMESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_RECAST;
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
CD_MASK_MTEXPOLY | CD_MASK_NORMAL | CD_MASK_RECAST;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_RECAST;
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL | CD_MASK_RECAST;
const CustomDataMask CD_MASK_BMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
CD_MASK_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_WEIGHT_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_WEIGHT_MCOL | CD_MASK_NORMAL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX;
const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS;
const CustomDataMask CD_MASK_FACECORNERS =
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL;
@ -1140,6 +1252,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
void *data;
int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, lastflag = 0;
for(i = 0; i < source->totlayer; ++i) {
@ -1164,14 +1277,27 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
else if(!(mask & CD_TYPE_AS_MASK(type))) continue;
else if(number < CustomData_number_of_layers(dest, type)) continue;
switch (alloctype) {
case CD_ASSIGN:
case CD_REFERENCE:
case CD_DUPLICATE:
data = layer->data;
break;
default:
data = NULL;
break;
}
if((alloctype == CD_ASSIGN) && (lastflag & CD_FLAG_NOFREE))
newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
layer->data, totelem, layer->name);
data, totelem, layer->name);
else
newlayer = customData_add_layer__internal(dest, type, alloctype,
layer->data, totelem, layer->name);
data, totelem, layer->name);
if(newlayer) {
newlayer->uid = layer->uid;
newlayer->active = lastactive;
newlayer->active_rnd = lastrender;
newlayer->active_clone = lastclone;
@ -1473,7 +1599,14 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
{
const LayerTypeInfo *typeInfo= layerType_getInfo(type);
int size = typeInfo->size * totelem, flag = 0, index = data->totlayer;
void *newlayerdata;
void *newlayerdata = NULL;
/* Passing a layerdata to copy from with an alloctype that won't copy is
most likely a bug */
BLI_assert(!layerdata ||
(alloctype == CD_ASSIGN) ||
(alloctype == CD_DUPLICATE) ||
(alloctype == CD_REFERENCE));
if (!typeInfo->defaultname && CustomData_has_layer(data, type))
return &data->layers[CustomData_get_layer_index(data, type)];
@ -1481,13 +1614,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
newlayerdata = layerdata;
}
else {
else if (size > 0) {
newlayerdata = MEM_callocN(size, layerType_getName(type));
if(!newlayerdata)
return NULL;
}
if (alloctype == CD_DUPLICATE) {
if (alloctype == CD_DUPLICATE && layerdata) {
if(typeInfo->copy)
typeInfo->copy(layerdata, newlayerdata, totelem);
else
@ -2304,35 +2437,142 @@ void CustomData_from_em_block(const CustomData *source, CustomData *dest,
/*Bmesh functions*/
/*needed to convert to/from different face reps*/
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata)
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
int totloop, int totpoly)
{
int i;
for(i=0; i < fdata->totlayer; i++){
if(fdata->layers[i].type == CD_MTFACE){
CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), 0);
CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), 0);
for(i=0; i < fdata->totlayer; i++) {
if(fdata->layers[i].type == CD_MTFACE) {
CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name);
CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
else if(fdata->layers[i].type == CD_MCOL)
CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
}
else if (fdata->layers[i].type == CD_MCOL) {
CustomData_add_layer_named(ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MDISPS) {
CustomData_add_layer_named(ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
}
}
void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total)
{
int i;
for(i=0; i < pdata->totlayer; i++){
if(pdata->layers[i].type == CD_MTEXPOLY)
CustomData_add_layer(fdata, CD_MTFACE, CD_CALLOC, &(pdata->layers[i].name), total);
for(i=0; i < pdata->totlayer; i++) {
if (pdata->layers[i].type == CD_MTEXPOLY) {
CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name);
}
}
for(i=0; i < ldata->totlayer; i++){
if(ldata->layers[i].type == CD_MLOOPCOL)
CustomData_add_layer(fdata, CD_MCOL, CD_CALLOC, &(ldata->layers[i].name), total);
for(i=0; i < ldata->totlayer; i++) {
if (ldata->layers[i].type == CD_MLOOPCOL) {
CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_WEIGHT_MLOOPCOL) {
CustomData_add_layer_named(fdata, CD_WEIGHT_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
CustomData_add_layer_named(fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
}
}
void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
{
int act;
if (CustomData_has_layer(pdata, CD_MTEXPOLY)) {
act = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
CustomData_set_layer_active(fdata, CD_MTFACE, act);
act = CustomData_get_render_layer(pdata, CD_MTEXPOLY);
CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
CustomData_set_layer_render(fdata, CD_MTFACE, act);
act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY);
CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
CustomData_set_layer_clone(fdata, CD_MTFACE, act);
act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY);
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
}
if (CustomData_has_layer(ldata, CD_MLOOPCOL)) {
act = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
CustomData_set_layer_active(fdata, CD_MCOL, act);
act = CustomData_get_render_layer(ldata, CD_MLOOPCOL);
CustomData_set_layer_render(fdata, CD_MCOL, act);
act = CustomData_get_clone_layer(ldata, CD_MLOOPCOL);
CustomData_set_layer_clone(fdata, CD_MCOL, act);
act = CustomData_get_stencil_layer(ldata, CD_MLOOPCOL);
CustomData_set_layer_stencil(fdata, CD_MCOL, act);
}
}
void CustomData_bmesh_init_pool(CustomData *data, int allocsize)
{
if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, FALSE, FALSE);
/* Dispose old pools before calling here to avoid leaks */
BLI_assert(data->pool == NULL);
/* If there are no layers, no pool is needed just yet */
if (data->totlayer) {
data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, TRUE, FALSE);
}
}
void CustomData_bmesh_merge(CustomData *source, CustomData *dest,
int mask, int alloctype, BMesh *bm, int type)
{
BMHeader *h;
BMIter iter;
CustomData destold = *dest;
void *tmp;
int t;
CustomData_merge(source, dest, mask, alloctype, 0);
CustomData_bmesh_init_pool(dest, 512);
switch (type) {
case BM_VERT:
t = BM_VERTS_OF_MESH; break;
case BM_EDGE:
t = BM_EDGES_OF_MESH; break;
case BM_LOOP:
t = BM_LOOPS_OF_FACE; break;
case BM_FACE:
t = BM_FACES_OF_MESH; break;
default: /* should never happen */
BLI_assert(!"invalid type given");
t = BM_VERTS_OF_MESH;
}
if (t != BM_LOOPS_OF_FACE) {
/*ensure all current elements follow new customdata layout*/
BM_ITER(h, &iter, bm, t, NULL) {
CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
CustomData_bmesh_free_block(&destold, &h->data);
h->data = tmp;
}
} else {
BMFace *f;
BMLoop *l;
BMIter liter;
/*ensure all current elements follow new customdata layout*/
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
CustomData_bmesh_free_block(&destold, &l->head.data);
l->head.data = tmp;
}
}
}
if (destold.pool) BLI_mempool_destroy(destold.pool);
}
void CustomData_bmesh_free_block(CustomData *data, void **block)
@ -2352,7 +2592,9 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
}
}
BLI_mempool_free(data->pool, *block);
if (data->totsize)
BLI_mempool_free(data->pool, *block);
*block = NULL;
}
@ -2363,7 +2605,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
CustomData_bmesh_free_block(data, block);
if (data->totsize > 0)
*block = BLI_mempool_calloc(data->pool);
*block = BLI_mempool_alloc(data->pool);
else
*block = NULL;
}
@ -2444,6 +2686,73 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return (char *)block + data->layers[n].offset;
}
int CustomData_layer_has_math(struct CustomData *data, int layern)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layern].type);
if (typeInfo->equal && typeInfo->add && typeInfo->multiply &&
typeInfo->initminmax && typeInfo->dominmax) return 1;
return 0;
}
/*copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
another, while not overwriting anything else (e.g. flags)*/
void CustomData_data_copy_value(int type, void *source, void *dest)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if(!dest) return;
if(typeInfo->copyvalue)
typeInfo->copyvalue(source, dest);
else
memcpy(dest, source, typeInfo->size);
}
int CustomData_data_equals(int type, void *data1, void *data2)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->equal)
return typeInfo->equal(data1, data2);
else return !memcmp(data1, data2, typeInfo->size);
}
void CustomData_data_initminmax(int type, void *min, void *max)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->initminmax)
typeInfo->initminmax(min, max);
}
void CustomData_data_dominmax(int type, void *data, void *min, void *max)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->dominmax)
typeInfo->dominmax(data, min, max);
}
void CustomData_data_multiply(int type, void *data, float fac)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->multiply)
typeInfo->multiply(data, fac);
}
void CustomData_data_add(int type, void *data1, void *data2)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->add)
typeInfo->add(data1, data2);
}
void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *source)
{

@ -432,6 +432,8 @@ void filldisplist(ListBase *dispbase, ListBase *to, int flipnormal)
totvert= 0;
nextcol= 0;
BLI_begin_edgefill();
dl= dispbase->first;
while(dl) {
@ -890,7 +892,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm = tdm;
CDDM_apply_vert_coords(dm, vertCos);
CDDM_calc_normals(dm);
CDDM_calc_normals_mapping(dm);
}
} else {
if (vertCos) {
@ -903,7 +905,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm= CDDM_from_curve_customDB(ob, dispbase);
CDDM_calc_normals(dm);
CDDM_calc_normals_mapping(dm);
}
if (vertCos) {
@ -931,7 +933,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm = tdm;
CDDM_apply_vert_coords(dm, vertCos);
CDDM_calc_normals(dm);
CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
} else {
displist_apply_allverts(dispbase, vertCos);
@ -941,6 +943,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
}
if (derivedFinal) {
if (dm) DM_ensure_tessface(dm); /* needed for drawing */
(*derivedFinal) = dm;
}

@ -1227,6 +1227,7 @@ static int surface_usesAdjData(DynamicPaintSurface *surface)
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
{
PaintSurfaceData *sData = surface->data;
DerivedMesh *dm = surface->canvas->dm;
PaintAdjData *ad;
int *temp_data;
int neigh_points = 0;
@ -1235,7 +1236,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbours are connected by edges */
neigh_points = 2*surface->canvas->dm->getNumEdges(surface->canvas->dm);
neigh_points = 2*dm->getNumEdges(dm);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
neigh_points = sData->total_points*8;
@ -1265,10 +1266,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int n_pos;
/* For vertex format, count every vertex that is connected by an edge */
int numOfEdges = surface->canvas->dm->getNumEdges(surface->canvas->dm);
int numOfFaces = surface->canvas->dm->getNumFaces(surface->canvas->dm);
struct MEdge *edge = surface->canvas->dm->getEdgeArray(surface->canvas->dm);
struct MFace *face = surface->canvas->dm->getFaceArray(surface->canvas->dm);
int numOfEdges = dm->getNumEdges(dm);
int numOfPolys = dm->getNumPolys(dm);
struct MEdge *edge = dm->getEdgeArray(dm);
struct MPoly *mpoly = dm->getPolyArray(dm);
struct MLoop *mloop = dm->getLoopArray(dm);
/* count number of edges per vertex */
for (i=0; i<numOfEdges; i++) {
@ -1281,12 +1283,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* also add number of vertices to temp_data
* to locate points on "mesh edge" */
for (i=0; i<numOfFaces; i++) {
temp_data[face[i].v1]++;
temp_data[face[i].v2]++;
temp_data[face[i].v3]++;
if (face[i].v4)
temp_data[face[i].v4]++;
for (i=0; i<numOfPolys; i++) {
int j=0;
for (; j<mpoly[i].totloop; j++) {
temp_data[mloop[mpoly[i].loopstart + j].v]++;
}
}
/* now check if total number of edges+faces for
@ -1355,8 +1356,8 @@ void dynamicPaint_setInitialColor(DynamicPaintSurface *surface)
else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
Tex *tex = surface->init_texture;
MTFace *tface;
MFace *mface = dm->getFaceArray(dm);
int numOfFaces = dm->getNumFaces(dm);
MFace *mface = dm->getTessFaceArray(dm);
int numOfFaces = dm->getNumTessFaces(dm);
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
if (!tex) return;
@ -1425,31 +1426,27 @@ void dynamicPaint_setInitialColor(DynamicPaintSurface *surface)
}
/* vertex color layer */
else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
if (!col) return;
/* for vertex surface, just copy colors from mcol */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
MFace *mface = dm->getFaceArray(dm);
int numOfFaces = dm->getNumFaces(dm);
MLoop *mloop = dm->getLoopArray(dm);
int numOfLoops = dm->getNumLoops(dm);
MCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
if (!col) return;
#pragma omp parallel for schedule(static)
for (i=0; i<numOfFaces; i++) {
int numOfVert = (mface[i].v4) ? 4 : 3;
int j;
for (j=0; j<numOfVert; j++) {
unsigned int *vert = ((&mface[i].v1)+j);
pPoint[*vert].color[0] = 1.0f/255.f*(float)col[i*4+j].b;
pPoint[*vert].color[1] = 1.0f/255.f*(float)col[i*4+j].g;
pPoint[*vert].color[2] = 1.0f/255.f*(float)col[i*4+j].r;
pPoint[*vert].alpha = 1.0f/255.f*(float)col[i*4+j].a;
}
for (i=0; i<numOfLoops; i++) {
pPoint[mloop[i].v].color[0] = 1.0f/255.f*(float)col[i].b;
pPoint[mloop[i].v].color[1] = 1.0f/255.f*(float)col[i].g;
pPoint[mloop[i].v].color[2] = 1.0f/255.f*(float)col[i].r;
pPoint[mloop[i].v].alpha = 1.0f/255.f*(float)col[i].a;
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data;
int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
if (!col) return;
#pragma omp parallel for schedule(static)
for (i=0; i<sData->total_points; i++) {
@ -1595,11 +1592,11 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
MFace *mface = result->getFaceArray(result);
int numOfFaces = result->getNumFaces(result);
int i;
PaintPoint* pPoint = (PaintPoint*)sData->type_data;
MCol *col;
MLoopCol *col = NULL;
MLoop *mloop = CDDM_get_loops(result);
int totloop = result->numLoopData;
/* paint is stored on dry and wet layers, so mix final color first */
float *fcolor = MEM_callocN(sizeof(float)*sData->total_points*4, "Temp paint color");
@ -1612,26 +1609,37 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* viewport preview */
if (surface->flags & MOD_DPAINT_PREVIEW) {
/* Save preview results to weight layer, to be
MPoly *mp = CDDM_get_polys(result);
int totpoly = result->numPolyData;
/* XXX We have to create a CD_WEIGHT_MCOL, else it might sigsev
* (after a SubSurf mod, eg)... */
if(!result->getTessFaceDataArray(result, CD_WEIGHT_MCOL)) {
int numFaces = result->getNumTessFaces(result);
CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numFaces);
}
/* Save preview results to weight layer to be
* able to share same drawing methods */
col = result->getFaceDataArray(result, CD_WEIGHT_MCOL);
if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces);
col = CustomData_get_layer(&result->loopData, CD_WEIGHT_MLOOPCOL);
if (!col) col = CustomData_add_layer(&result->loopData, CD_WEIGHT_MLOOPCOL, CD_CALLOC, NULL, totloop);
if (col) {
#pragma omp parallel for schedule(static)
for (i=0; i<numOfFaces; i++) {
int j = (mface[i].v4) ? 4 : 3;
Material *material = give_current_material(ob, mface[i].mat_nr+1);
for (i=0; i<totpoly; i++) {
int j=0;
Material *material = give_current_material(ob, mp[i].mat_nr+1);
while (j--) {
int index = *((&mface[i].v1)+j);
for (; j<mp[i].totloop; j++) {
int l_index = mp[i].loopstart + j;
int v_index = mloop[l_index].v;
if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
float c[3];
index *= 4;
v_index *= 4;
/* Apply material color as base vertex color for preview */
col[i*4+j].a = 255;
col[l_index].a = 255;
if (material) {
c[0] = material->r;
c[1] = material->g;
@ -1643,17 +1651,17 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
c[2] = 0.65f;
}
/* mix surface color */
interp_v3_v3v3(c, c, &fcolor[index], fcolor[index+3]);
interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index+3]);
col[i*4+j].r = FTOCHAR(c[2]);
col[i*4+j].g = FTOCHAR(c[1]);
col[i*4+j].b = FTOCHAR(c[0]);
col[l_index].r = FTOCHAR(c[2]);
col[l_index].g = FTOCHAR(c[1]);
col[l_index].b = FTOCHAR(c[0]);
}
else {
col[i*4+j].a = 255;
col[i*4+j].r =
col[i*4+j].g =
col[i*4+j].b = FTOCHAR(pPoint[index].wetness);
col[l_index].a = 255;
col[l_index].r =
col[l_index].g =
col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
}
}
}
@ -1664,46 +1672,38 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* save layer data to output layer */
/* paint layer */
col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name);
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name);
col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
for (i=0; i<numOfFaces; i++) {
int j = (mface[i].v4) ? 4 : 3;
while (j--) {
int index = *((&mface[i].v1)+j);
index *= 4;
col[i*4+j].a = FTOCHAR(fcolor[index+3]);
col[i*4+j].r = FTOCHAR(fcolor[index+2]);
col[i*4+j].g = FTOCHAR(fcolor[index+1]);
col[i*4+j].b = FTOCHAR(fcolor[index]);
}
for (i=0; i<totloop; i++) {
int index = mloop[i].v*4;
col[i].a = FTOCHAR(fcolor[index+3]);
col[i].r = FTOCHAR(fcolor[index+2]);
col[i].g = FTOCHAR(fcolor[index+1]);
col[i].b = FTOCHAR(fcolor[index]);
}
}
MEM_freeN(fcolor);
/* wet layer */
col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name2);
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name2);
col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
for (i=0; i<numOfFaces; i++) {
int j = (mface[i].v4) ? 4 : 3;
while (j--) {
int index = *((&mface[i].v1)+j);
col[i*4+j].a = 255;
col[i*4+j].r =
col[i*4+j].g =
col[i*4+j].b = FTOCHAR(pPoint[index].wetness);
}
for (i=0; i<totloop; i++) {
int index = mloop[i].v;
col[i].a = 255;
col[i].r =
col[i].g =
col[i].b = FTOCHAR(pPoint[index].wetness);
}
}
}
@ -1712,9 +1712,10 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
int defgrp_index = defgroup_name_index(ob, surface->output_name);
MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
float *weight = (float*)sData->type_data;
/* viewport preview */
if (surface->flags & MOD_DPAINT_PREVIEW) {
/* Save preview results to weight layer, to be
/* Save preview results to weight layer to be
* able to share same drawing methods */
DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
}
@ -1873,6 +1874,10 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
/* For now generate tessfaces in every case
* XXX - move/remove when most of dpaint functions are converted to use bmesh types */
DM_ensure_tessface(dm);
/* Update canvas data for a new frame */
dynamicPaint_frameUpdate(pmd, scene, ob, dm);
@ -1945,8 +1950,8 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
* TODO: Implement something more accurate / optimized?
*/
{
int numOfFaces = dm->getNumFaces(dm);
MFace *mface = dm->getFaceArray(dm);
int numOfFaces = dm->getNumTessFaces(dm);
MFace *mface = dm->getTessFaceArray(dm);
MTFace *tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
/* Get closest edge to that subpixel on UV map */
@ -2112,8 +2117,8 @@ int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
if (!dm) return setError(canvas, "Canvas mesh not updated.");
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) return setError(canvas, "Can't bake non-\"image sequence\" formats.");
numOfFaces = dm->getNumFaces(dm);
mface = dm->getFaceArray(dm);
numOfFaces = dm->getNumTessFaces(dm);
mface = dm->getTessFaceArray(dm);
/* get uv map */
CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname);
@ -2708,7 +2713,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm)
{
Material *mat = bMats->mat;
MFace *mface = orcoDm->getFaceArray(orcoDm);
MFace *mface = orcoDm->getTessFaceArray(orcoDm);
/* If no material defined, use the one assigned to the mesh face */
if (mat == NULL) {
@ -3147,7 +3152,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
dm = CDDM_copy(brush->dm);
mvert = dm->getVertArray(dm);
mface = dm->getFaceArray(dm);
mface = dm->getTessFaceArray(dm);
numOfVerts = dm->getNumVerts(dm);
/* Transform collider vertices to global space

File diff suppressed because it is too large Load Diff

@ -553,7 +553,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa
}
if(surface_vel) {
MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index);
copy_v3_v3(surface_vel, surmd->v[mface->v1].co);
add_v3_v3(surface_vel, surmd->v[mface->v2].co);

@ -85,9 +85,9 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
//dm = mesh_create_derived_no_deform(ob,NULL);
mvert = dm->getVertArray(dm);
mface = dm->getFaceArray(dm);
mface = dm->getTessFaceArray(dm);
totvert = dm->getNumVerts(dm);
totface = dm->getNumFaces(dm);
totface = dm->getNumTessFaces(dm);
*numVertices = totvert;
verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");

@ -382,6 +382,25 @@ void make_local_image(struct Image *ima)
}
}
}
if(me->mtpoly) {
MTexPoly *mtpoly;
int a, i;
for(i=0; i<me->pdata.totlayer; i++) {
if(me->pdata.layers[i].type == CD_MTEXPOLY) {
mtpoly= (MTexPoly*)me->pdata.layers[i].data;
for(a=0; a<me->totpoly; a++, mtpoly++) {
if(mtpoly->tpage == ima) {
if(me->id.lib) is_lib= TRUE;
else is_local= TRUE;
}
}
}
}
}
}
if(is_local && is_lib == FALSE) {
@ -443,6 +462,28 @@ void make_local_image(struct Image *ima)
}
}
}
if(me->mtpoly) {
MTexPoly *mtpoly;
int a, i;
for(i=0; i<me->pdata.totlayer; i++) {
if(me->pdata.layers[i].type == CD_MTEXPOLY) {
mtpoly= (MTexPoly*)me->pdata.layers[i].data;
for(a=0; a<me->totpoly; a++, mtpoly++) {
if(mtpoly->tpage == ima) {
mtpoly->tpage = ima_new;
if(ima_new->id.us == 0) {
mtpoly->tpage->id.us= 1;
}
id_lib_extern((ID*)ima_new);
}
}
}
}
}
me= me->id.next;
}
}

@ -56,6 +56,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_tessmesh.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_deform.h"
@ -92,6 +93,20 @@ void free_key(Key *key)
}
void free_key_nolib(Key *key)
{
KeyBlock *kb;
while( (kb= key->block.first) ) {
if(kb->data) MEM_freeN(kb->data);
BLI_remlink(&key->block, kb);
MEM_freeN(kb);
}
}
/* GS reads the memory pointed at in a specific ordering. There are,
* however two definitions for it. I have jotted them down here, both,
* but I think the first one is actually used. The thing is that
@ -114,6 +129,8 @@ Key *add_key(ID *id) /* common function */
key->type= KEY_NORMAL;
key->from= id;
key->uidgen = 1;
// XXX the code here uses some defines which will soon be depreceated...
if( GS(id->name)==ID_ME) {
@ -172,6 +189,34 @@ Key *copy_key(Key *key)
return keyn;
}
Key *copy_key_nolib(Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
if(key==0) return 0;
keyn= MEM_dupallocN(key);
keyn->adt = NULL;
BLI_duplicatelist(&keyn->block, &key->block);
kb= key->block.first;
kbn= keyn->block.first;
while(kbn) {
if(kbn->data) kbn->data= MEM_dupallocN(kbn->data);
if(kb==key->refkey) keyn->refkey= kbn;
kbn= kbn->next;
kb= kb->next;
}
return keyn;
}
void make_local_key(Key *key)
{
@ -495,18 +540,21 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
edit mode with shape keys blending applied */
if(GS(key->from->name) == ID_ME) {
Mesh *me;
EditVert *eve;
BMVert *eve;
BMIter iter;
float (*co)[3];
int a;
me= (Mesh*)key->from;
if(me->edit_mesh && me->edit_mesh->totvert == kb->totelem) {
if(me->edit_btmesh && me->edit_btmesh->bm->totvert == kb->totelem) {
a= 0;
co= MEM_callocN(sizeof(float)*3*me->edit_mesh->totvert, "key_block_get_data");
co= MEM_callocN(sizeof(float)*3*me->edit_btmesh->bm->totvert, "key_block_get_data");
for(eve=me->edit_mesh->verts.first; eve; eve=eve->next, a++)
BM_ITER(eve, &iter, me->edit_btmesh->bm, BM_VERTS_OF_MESH, NULL) {
copy_v3_v3(co[a], eve->co);
a++;
}
*freedata= (char*)co;
return (char*)co;
@ -1000,8 +1048,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
static float *get_weights_array(Object *ob, char *vgroup)
{
MDeformVert *dvert= NULL;
EditMesh *em= NULL;
EditVert *eve;
BMEditMesh *em= NULL;
BMIter iter;
BMVert *eve;
int totvert= 0, defgrp_index= 0;
/* no vgroup string set? */
@ -1013,8 +1062,8 @@ static float *get_weights_array(Object *ob, char *vgroup)
dvert= me->dvert;
totvert= me->totvert;
if(me->edit_mesh && me->edit_mesh->totvert == totvert)
em= me->edit_mesh;
if(me->edit_btmesh && me->edit_btmesh->bm->totvert == totvert)
em= me->edit_btmesh;
}
else if(ob->type==OB_LATTICE) {
Lattice *lt= ob->data;
@ -1033,8 +1082,9 @@ static float *get_weights_array(Object *ob, char *vgroup)
weights= MEM_callocN(totvert*sizeof(float), "weights");
if(em) {
for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) {
dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
for (i=0; eve; eve=BM_iter_step(&iter), i++) {
dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
weights[i]= defvert_find_weight(dvert, defgrp_index);
@ -1451,7 +1501,8 @@ KeyBlock *add_keyblock(Key *key, const char *name)
// XXX this is old anim system stuff? (i.e. the 'index' of the shapekey)
kb->adrcode= tot-1;
kb->uid = key->uidgen++;
key->totkey++;
if(key->totkey==1) key->refkey= kb;

@ -820,7 +820,7 @@ void free_libblock(ListBase *lb, void *idv)
free_object((Object *)id);
break;
case ID_ME:
free_mesh((Mesh *)id);
free_mesh((Mesh *)id, 1);
break;
case ID_CU:
free_curve((Curve *)id);

File diff suppressed because it is too large Load Diff

@ -451,11 +451,11 @@ int BKE_mesh_validate(Mesh *me, int do_verbose)
int BKE_mesh_validate_dm(DerivedMesh *dm)
{
return BKE_mesh_validate_arrays(NULL,
dm->getVertArray(dm), dm->getNumVerts(dm),
dm->getEdgeArray(dm), dm->getNumEdges(dm),
dm->getFaceArray(dm), dm->getNumFaces(dm),
dm->getVertDataArray(dm, CD_MDEFORMVERT),
TRUE, FALSE);
dm->getVertArray(dm), dm->getNumVerts(dm),
dm->getEdgeArray(dm), dm->getNumEdges(dm),
dm->getTessFaceArray(dm), dm->getNumTessFaces(dm),
dm->getVertDataArray(dm, CD_MDEFORMVERT),
TRUE, FALSE);
}
void BKE_mesh_calc_edges(Mesh *mesh, int update)
@ -466,6 +466,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
MEdge *med, *med_orig;
EdgeHash *eh = BLI_edgehash_new();
int i, totedge, totface = mesh->totface;
int med_index;
if(mesh->totedge==0)
update= 0;
@ -478,20 +479,37 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
BLI_edgehash_insert(eh, med->v1, med->v2, med);
}
for (i = 0; i < totface; i++, mf++) {
if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
if(mesh->totpoly) {
/* mesh loops (bmesh only) */
MPoly *mp= mesh->mpoly;
for(i=0; i < mesh->totpoly; i++, mp++) {
MLoop *l= &mesh->mloop[mp->loopstart];
int j, l_prev= (l + (mp->totloop-1))->v;
for (j=0; j < mp->totloop; j++, l++) {
if (!BLI_edgehash_haskey(eh, l_prev, l->v)) {
BLI_edgehash_insert(eh, l_prev, l->v, NULL);
}
l_prev= l->v;
}
}
}
else {
/* regular faces (note, we could remove this for bmesh - campbell) */
for (i = 0; i < totface; i++, mf++) {
if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
if (mf->v4) {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
} else {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
if (mf->v4) {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
} else {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
}
}
}
@ -512,9 +530,29 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
med->flag = ME_EDGEDRAW|ME_EDGERENDER|SELECT; /* select for newly created meshes which are selected [#25595] */
}
/* store the new edge index in the hash value */
BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
}
BLI_edgehashIterator_free(ehi);
if (mesh->totpoly) {
/* second pass, iterate through all loops again and assign
the newly created edges to them. */
MPoly *mp= mesh->mpoly;
for(i=0; i < mesh->totpoly; i++, mp++) {
MLoop *l= &mesh->mloop[mp->loopstart];
MLoop *l_prev= (l + (mp->totloop-1));
int j;
for (j=0; j < mp->totloop; j++, l++) {
/* lookup hashed edge index */
med_index = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, l_prev->v, l->v));
l_prev->e = med_index;
l_prev= l;
}
}
}
/* free old CustomData and assign new one */
CustomData_free(&mesh->edata, mesh->totedge);
mesh->edata = edata;

@ -0,0 +1,171 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*
* Contributor(s): Joseph Eagar
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/** \file blender/blenkernel/intern/modifiers_bmesh.c
* \ingroup bke
*/
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "BLI_array.h"
#include "BKE_bmesh.h"
#include "BKE_tessmesh.h"
/* main function for copying DerivedMesh data into BMesh */
void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm)
{
MVert *mv, *mvert;
MEdge *me, *medge;
MPoly *mpoly, *mp;
MLoop *mloop, *ml;
BMVert *v, **vtable, **verts = NULL;
BMEdge *e, **etable, **edges = NULL;
BMFace *f;
BMIter liter;
BLI_array_declare(verts);
BLI_array_declare(edges);
int i, j, k, totvert, totedge, totface;
/*merge custom data layout*/
CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumPolys(dm);
vtable = MEM_callocN(sizeof(void**) * totvert, "vert table in BMDM_Copy");
etable = MEM_callocN(sizeof(void**) * totedge, "edge table in BMDM_Copy");
/*do verts*/
mv = mvert = dm->dupVertArray(dm);
for (i = 0; i < totvert; i++, mv++) {
v = BM_vert_create(bm, mv->co, NULL);
normal_short_to_float_v3(v->no, mv->no);
v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data);
vtable[i] = v;
}
MEM_freeN(mvert);
/*do edges*/
me = medge = dm->dupEdgeArray(dm);
for (i = 0; i < totedge; i++, me++) {
e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, FALSE);
e->head.hflag = BM_edge_flag_from_mflag(me->flag);
CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
etable[i] = e;
}
MEM_freeN(medge);
/*do faces*/
mpoly = mp = dm->getPolyArray(dm);
mloop = dm->getLoopArray(dm);
for (i = 0; i < dm->numPolyData; i++, mp++) {
BMLoop *l;
BLI_array_empty(verts);
BLI_array_empty(edges);
BLI_array_growitems(verts, mp->totloop);
BLI_array_growitems(edges, mp->totloop);
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++) {
verts[j] = vtable[ml->v];
edges[j] = etable[ml->e];
}
f = BM_face_create_ngon(bm, verts[0], verts[1], edges, mp->totloop, FALSE);
if (!f)
continue;
f->head.hflag = BM_face_flag_from_mflag(mp->flag);
f->mat_nr = mp->mat_nr;
l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
k = mp->loopstart;
for (j = 0; l; l = BM_iter_step(&liter), k++) {
CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
}
CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data);
}
MEM_freeN(vtable);
MEM_freeN(etable);
BLI_array_free(verts);
BLI_array_free(edges);
}
/* converts a cddm to a BMEditMesh. if existing is non-NULL, the
* new geometry will be put in there.*/
BMEditMesh *DM_to_editbmesh(Object *ob, DerivedMesh *dm, BMEditMesh *existing, int do_tesselate)
{
BMEditMesh *em = existing;
BMesh *bm;
if (em) bm = em->bm;
else bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
DM_to_bmesh_ex(dm, bm);
if (!em) {
em = BMEdit_Create(bm, do_tesselate);
}
else {
if (do_tesselate) {
BMEdit_RecalcTesselation(em);
}
}
return em;
}
BMesh *DM_to_bmesh(Object *ob, DerivedMesh *dm)
{
BMesh *bm;
bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
DM_to_bmesh_ex(dm, bm);
return bm;
}

@ -53,6 +53,7 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_tessmesh.h"
#include "BKE_object.h"
@ -67,7 +68,7 @@ static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641,
static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, int invert, int add, DMGridData **oldGridData, int totlvl);
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
@ -180,7 +181,7 @@ void multires_force_external_reload(Object *ob)
{
Mesh *me = get_mesh(ob);
CustomData_external_reload(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
multires_force_update(ob);
}
@ -256,26 +257,31 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
static int get_levels_from_disps(Object *ob)
{
Mesh *me = ob->data;
MDisps *mdisp;
int i, totlvl= 0;
MDisps *mdisp, *md;
int i, j, totlvl= 0;
mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
for(i = 0; i < me->totface; ++i, ++mdisp) {
int S = me->mface[i].v4 ? 4 : 3;
if(mdisp->totdisp == 0) continue;
while(1) {
int side = (1 << (totlvl-1)) + 1;
int lvl_totdisp = side*side*S;
if(mdisp->totdisp == lvl_totdisp)
break;
else if(mdisp->totdisp < lvl_totdisp)
--totlvl;
else
++totlvl;
mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
for(i = 0; i < me->totpoly; ++i) {
int S = me->mpoly[i].totloop;
md = mdisp + me->mpoly[i].loopstart;
for (j=0; j<me->mpoly[i].totloop; j++, md++) {
if(md->totdisp == 0) continue;
while(1) {
int side = (1 << (totlvl-1)) + 1;
int lvl_totdisp = side*side*S;
if(md->totdisp == lvl_totdisp)
break;
else if(md->totdisp < lvl_totdisp)
--totlvl;
else
++totlvl;
}
break;
}
}
@ -288,10 +294,10 @@ void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *o
Mesh *me = ob->data;
MDisps *mdisp;
if(me->edit_mesh)
mdisp = CustomData_get_layer(&me->edit_mesh->fdata, CD_MDISPS);
if(me->edit_btmesh)
mdisp = CustomData_get_layer(&me->edit_btmesh->bm->ldata, CD_MDISPS);
else
mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(mdisp) {
mmd->totlvl = get_levels_from_disps(ob);
@ -303,27 +309,23 @@ void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *o
static void multires_set_tot_mdisps(Mesh *me, int lvl)
{
MDisps *mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
MDisps *mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
int i;
if(mdisps) {
for(i = 0; i < me->totface; i++) {
if(mdisps[i].totdisp == 0) {
int nvert = (me->mface[i].v4)? 4: 3;
mdisps[i].totdisp = multires_grid_tot[lvl]*nvert;
}
for(i = 0; i < me->totloop; i++, mdisps++) {
mdisps->totdisp = multires_grid_tot[lvl];
}
}
}
static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl)
{
int i;
/* reallocate displacements to be filled in */
for(i = 0; i < me->totface; ++i) {
int nvert = (me->mface[i].v4)? 4: 3;
int totdisp = multires_grid_tot[lvl]*nvert;
for(i = 0; i < totloop; ++i) {
int totdisp = multires_grid_tot[lvl];
float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
if(mdisps[i].disps)
@ -388,44 +390,43 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
MDisps *mdisps;
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
multires_force_update(ob);
if(mdisps && levels > 0) {
if(lvl > 0) {
/* MLoop *ml = me->mloop; */ /*UNUSED*/
int nsize = multires_side_tot[lvl];
int hsize = multires_side_tot[mmd->totlvl];
int i;
int i, j;
for(i = 0; i < me->totface; ++i) {
MDisps *mdisp= &mdisps[i];
float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
int nvert = (me->mface[i].v4)? 4: 3;
int totdisp = multires_grid_tot[lvl]*nvert;
int S;
for(i = 0; i < me->totpoly; ++i) {
for (j=0; j<me->mpoly[i].totloop; j++) {
MDisps *mdisp= &mdisps[me->mpoly[i].loopstart+j];
float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
int totdisp = multires_grid_tot[lvl];
disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
ndisps = disps;
hdisps = mdisp->disps;
ndisps = disps;
hdisps = mdisp->disps;
for(S = 0; S < nvert; S++) {
multires_copy_grid(ndisps, hdisps, nsize, hsize);
ndisps += nsize*nsize;
hdisps += hsize*hsize;
}
MEM_freeN(mdisp->disps);
mdisp->disps = disps;
mdisp->totdisp = totdisp;
MEM_freeN(mdisp->disps);
mdisp->disps = disps;
mdisp->totdisp = totdisp;
}
}
}
else {
CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop);
}
}
@ -441,8 +442,8 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
MDisps *mdisps;
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
multires_force_update(ob);
@ -597,7 +598,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
cddm->release(cddm);
/* calc disps */
multiresModifier_disp_run(dispdm, me, 1, 0, origdm->getGridData(origdm), totlvl);
multiresModifier_disp_run(dispdm, me, NULL, 1, 0, origdm->getGridData(origdm), totlvl);
origdm->release(origdm);
dispdm->release(dispdm);
@ -614,9 +615,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
multires_force_update(ob);
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(!mdisps)
mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
if(mdisps->disps && !updateblock && totlvl > 1) {
/* upsample */
@ -661,10 +662,10 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* reallocate displacements */
multires_reallocate_mdisps(me, mdisps, totlvl);
multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
/* compute displacements */
multiresModifier_disp_run(highdm, me, 1, 0, subGridData, totlvl);
multiresModifier_disp_run(highdm, me, NULL, 1, 0, subGridData, totlvl);
/* free */
highdm->release(highdm);
@ -674,7 +675,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
}
else {
/* only reallocate, nothing to upsample */
multires_reallocate_mdisps(me, mdisps, totlvl);
multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
}
multires_set_tot_level(ob, mmd, totlvl);
@ -685,7 +686,7 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
multires_subdivide(mmd, ob, mmd->totlvl+1, updateblock, simple);
}
static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
{
if(axis == 0) {
if(x == gridSize - 1) {
@ -709,18 +710,30 @@ static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGrid
}
}
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl)
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, int invert, int add, DMGridData **oldGridData, int totlvl)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
DMGridData **gridData, **subGridData;
MFace *mface = me->mface;
MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
MPoly *mpoly = me->mpoly;
MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
int *gridOffset;
int i, /*numGrids,*/ gridSize, dGridSize, dSkip;
int i, k, /*numGrids,*/ gridSize, dGridSize, dSkip;
int totloop, totpoly;
/*this happens in the dm made by bmesh_set_mdisps_space*/
if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) {
mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY);
mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS);
totloop = dm2->numLoopData;
totpoly = dm2->numPolyData;
} else {
totloop = me->totloop;
totpoly = me->totpoly;
}
if(!mdisps) {
if(invert)
mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
else
return;
}
@ -734,23 +747,28 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
dGridSize = multires_side_tot[totlvl];
dSkip = (dGridSize-1)/(gridSize-1);
#pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
for(i = 0; i < me->totface; ++i) {
const int numVerts = mface[i].v4 ? 4 : 3;
MDisps *mdisp = &mdisps[i];
k = 0; /*current loop/mdisp index within the mloop array*/
#pragma omp parallel for private(i) if(totloop*gridSize*gridSize >= CCG_OMP_LIMIT)
for(i = 0; i < totpoly; ++i) {
const int numVerts = mpoly[i].totloop;
int S, x, y, gIndex = gridOffset[i];
/* when adding new faces in edit mode, need to allocate disps */
if(!mdisp->disps)
#pragma omp critical
{
multires_reallocate_mdisps(me, mdisps, totlvl);
}
for(S = 0; S < numVerts; ++S, ++gIndex) {
for(S = 0; S < numVerts; ++S, ++gIndex, ++k) {
MDisps *mdisp = &mdisps[mpoly[i].loopstart+S];
DMGridData *grid = gridData[gIndex];
DMGridData *subgrid = subGridData[gIndex];
float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
float (*dispgrid)[3] = NULL;
/* when adding new faces in edit mode, need to allocate disps */
if(!mdisp->disps)
#pragma omp critical
{
multires_reallocate_mdisps(totloop, mdisps, totlvl);
}
dispgrid = mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
@ -813,8 +831,8 @@ static void multiresModifier_update(DerivedMesh *dm)
me = ccgdm->multires.ob->data;
mmd = ccgdm->multires.mmd;
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(mdisps) {
int lvl = ccgdm->multires.lvl;
@ -871,7 +889,7 @@ static void multiresModifier_update(DerivedMesh *dm)
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* add to displacements */
multiresModifier_disp_run(highdm, me, 1, 1, subGridData, mmd->totlvl);
multiresModifier_disp_run(highdm, me, NULL, 1, 1, subGridData, mmd->totlvl);
/* free */
highdm->release(highdm);
@ -889,13 +907,136 @@ static void multiresModifier_update(DerivedMesh *dm)
subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
multiresModifier_disp_run(dm, me, NULL, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
subdm->release(subdm);
}
}
}
void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
{
DerivedMesh *ccgdm = NULL, *subsurf = NULL;
DMGridData **gridData, **subGridData=NULL;
MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
MDisps *mdisps;
MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
int *gridOffset, totlvl;
int i, k, numGrids, gridSize, dGridSize, dSkip;
if (!mmd)
return;
mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
if(!mdisps) {
goto cleanup;
}
totlvl = mmd->totlvl;
ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple);
subsurf = subsurf_dm_create_local(ob, dm, totlvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv);
numGrids = subsurf->getNumGrids(subsurf);
gridSize = subsurf->getGridSize(subsurf);
gridData = subsurf->getGridData(subsurf);
subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
for(i = 0; i < numGrids; i++) {
subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
}
/*numGrids = ccgdm->dm->getNumGrids((DerivedMesh*)ccgdm);*/ /*UNUSED*/
gridSize = ccgdm->getGridSize((DerivedMesh*)ccgdm);
gridData = ccgdm->getGridData((DerivedMesh*)ccgdm);
gridOffset = ccgdm->getGridOffset((DerivedMesh*)ccgdm);
dGridSize = multires_side_tot[totlvl];
dSkip = (dGridSize-1)/(gridSize-1);
k = 0; /*current loop/mdisp index within the mloop array*/
//#pragma omp parallel for private(i) if(dm->numLoopData*gridSize*gridSize >= CCG_OMP_LIMIT)
for(i = 0; i < dm->numPolyData; ++i) {
const int numVerts = mpoly[i].totloop;
int S, x, y, gIndex = gridOffset[i];
for(S = 0; S < numVerts; ++S, ++gIndex, ++k) {
MDisps *mdisp = &mdisps[mpoly[i].loopstart+S];
/* DMGridData *grid = gridData[gIndex]; */ /* UNUSED */
DMGridData *subgrid = subGridData[gIndex];
float (*dispgrid)[3] = NULL;
/* when adding new faces in edit mode, need to allocate disps */
if(!mdisp->disps) {
mdisp->totdisp = gridSize*gridSize;
mdisp->disps = MEM_callocN(sizeof(float)*3*mdisp->totdisp, "disp in multires_set_space");
}
dispgrid = mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
float *no = subgrid[x + y*gridSize].no;
float *co = subgrid[x + y*gridSize].co;
float mat[3][3], tx[3], ty[3], dco[3];
/* construct tangent space matrix */
grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
normalize_v3(tx);
grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
normalize_v3(ty);
column_vectors_to_mat3(mat, tx, ty, no);
/* convert to absolute coordinates in space */
if (from == MULTIRES_SPACE_TANGENT) {
mul_v3_m3v3(dco, mat, data);
add_v3_v3(dco, co);
} else if (from == MULTIRES_SPACE_OBJECT) {
add_v3_v3v3(dco, co, data);
} else if (from == MULTIRES_SPACE_ABSOLUTE) {
copy_v3_v3(dco, data);
}
column_vectors_to_mat3(mat, tx, ty, no);
/*now, convert to desired displacement type*/
if (to == MULTIRES_SPACE_TANGENT) {
invert_m3(mat);
sub_v3_v3(dco, co);
mul_v3_m3v3(data, mat, dco);
} else if (to == MULTIRES_SPACE_OBJECT) {
sub_v3_v3(dco, co);
mul_v3_m3v3(data, mat, dco);
} else if (to == MULTIRES_SPACE_ABSOLUTE) {
copy_v3_v3(data, dco);
}
}
}
}
}
cleanup:
if (subsurf) {
subsurf->needsFree = 1;
subsurf->release(subsurf);
}
if (ccgdm) {
ccgdm->needsFree = 1;
ccgdm->release(ccgdm);
}
}
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
@ -956,8 +1097,10 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
}
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
/*run displacement*/
multiresModifier_disp_run(result, ob->data, dm, 0, 0, subGridData, mmd->totlvl);
for(i = 0; i < numGrids; i++)
MEM_freeN(subGridData[i]);
@ -976,7 +1119,10 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
const int st_max = st - 1;
float urat, vrat, uopp;
float d[4][3], d2[2][3];
if (!disps || isnan(u) || isnan(v))
return;
if(u < 0)
u = 0;
else if(u >= st)
@ -1057,15 +1203,33 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
void multires_load_old_250(Mesh *me)
{
MDisps *mdisps;
int a;
MDisps *mdisps, *mdisps2;
MFace *mf;
int i, j, k;
mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
if(mdisps) {
for(a=0; a<me->totface; a++)
if(mdisps[a].totdisp)
old_mdisps_convert(&me->mface[a], &mdisps[a]);
for(i=0; i<me->totface; i++)
if(mdisps[i].totdisp)
old_mdisps_convert(&me->mface[i], &mdisps[i]);
CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS);
k = 0;
mf = me->mface;
for (i=0; i<me->totface; i++, mf++) {
int nvert = mf->v4 ? 4 : 3;
int totdisp = mdisps[i].totdisp / nvert;
for (j=0; j < mf->v4 ? 4 : 3; j++, k++) {
mdisps2[k].disps = MEM_callocN(sizeof(float)*3*totdisp, "multires disp in conversion");
mdisps2[k].totdisp = totdisp;
memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp*j, totdisp);
}
}
}
}
@ -1590,8 +1754,8 @@ static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
Mesh *me= (Mesh*)ob->data;
CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop);
}
if(!mmd || !to_mmd) return;
@ -1605,7 +1769,8 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
DerivedMesh *dm= NULL, *cddm= NULL, *subdm= NULL;
DMGridData **gridData, **subGridData;
Mesh *me= (Mesh*)ob->data;
MFace *mface= me->mface;
MPoly *mpoly= me->mpoly;
/* MLoop *mloop = me->mloop; */ /* UNUSED */
MDisps *mdisps;
int *gridOffset;
int i, /*numGrids,*/ gridSize, dGridSize, dSkip, totvert;
@ -1613,8 +1778,8 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
MultiresModifierData high_mmd;
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
if(!mdisps || !mmd || !mmd->totlvl) return;
@ -1650,15 +1815,15 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
dSkip= (dGridSize-1)/(gridSize-1);
#pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
for(i = 0; i < me->totface; ++i) {
const int numVerts= mface[i].v4 ? 4 : 3;
MDisps *mdisp= &mdisps[i];
for(i = 0; i < me->totpoly; ++i) {
const int numVerts= mpoly[i].totloop;
MDisps *mdisp= &mdisps[mpoly[i].loopstart];
int S, x, y, gIndex = gridOffset[i];
for(S = 0; S < numVerts; ++S, ++gIndex) {
for(S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
DMGridData *grid= gridData[gIndex];
DMGridData *subgrid= subGridData[gIndex];
float (*dispgrid)[3]= &mdisp->disps[S*dGridSize*dGridSize];
float (*dispgrid)[3]= mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
@ -1731,6 +1896,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
}
/* update multires data after topology changing */
#if 0 // BMESH_TODO
void multires_topology_changed(Scene *scene, Object *ob)
{
Mesh *me= (Mesh*)ob->data;
@ -1781,6 +1947,7 @@ void multires_topology_changed(Scene *scene, Object *ob)
}
}
}
#endif // BMESH_TODO
/* makes displacement along grid boundary symmetrical */
void multires_mdisp_smooth_bounds(MDisps *disps)

@ -134,8 +134,8 @@ int buildRawVertIndicesData(DerivedMesh* dm, int *nverts_r, float **verts_r,
}
//calculate number of tris
nfaces = dm->getNumFaces(dm);
faces = dm->getFaceArray(dm);
nfaces = dm->getNumTessFaces(dm);
faces = dm->getTessFaceArray(dm);
ntris = nfaces;
for (fi=0; fi<nfaces; fi++)
{

@ -86,6 +86,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_tessmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@ -1722,7 +1723,7 @@ static void ob_parbone(Object *ob, Object *par, float mat[][4])
static void give_parvert(Object *par, int nr, float *vec)
{
EditMesh *em;
BMEditMesh *em;
int a, count;
vec[0]=vec[1]=vec[2]= 0.0f;
@ -1731,7 +1732,24 @@ static void give_parvert(Object *par, int nr, float *vec)
Mesh *me= par->data;
DerivedMesh *dm;
em = BKE_mesh_get_editmesh(me);
em = me->edit_btmesh;
#if 0 /* this was bmesh only, better, evaluate why this was needed - campbell*/
if(em) {
BMVert *eve;
BMIter iter;
BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
int *keyindex = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
if(keyindex && *keyindex==nr) {
copy_v3_v3(vec, eve->co);
break;
}
}
}
#endif
dm = (em)? em->derivedFinal: par->derivedFinal;
if(dm) {
@ -1760,9 +1778,6 @@ static void give_parvert(Object *par, int nr, float *vec)
}
}
else fprintf(stderr, "%s: DerivedMesh is needed to solve parenting, object position can be wrong now\n", __func__);
if(em)
BKE_mesh_end_editmesh(me, em);
}
else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
Nurb *nu;
@ -2522,22 +2537,24 @@ void object_handle_update(Scene *scene, Object *ob)
case OB_MESH:
{
#if 0 // XXX, comment for 2.56a release, background wont set 'scene->customdata_mask'
EditMesh *em = (ob == scene->obedit)? BKE_mesh_get_editmesh(ob->data): NULL;
BMEditMesh *em = (ob == scene->obedit)? ((Mesh*)ob->data)->edit_btmesh : NULL;
BLI_assert((scene->customdata_mask & CD_MASK_BAREMESH) == CD_MASK_BAREMESH);
if(em) {
makeDerivedMesh(scene, ob, em, scene->customdata_mask); /* was CD_MASK_BAREMESH */
BKE_mesh_end_editmesh(ob->data, em);
} else
makeDerivedMesh(scene, ob, NULL, scene->customdata_mask);
makeDerivedMesh(scene, ob, em, scene->customdata_mask, 0); /* was CD_MASK_BAREMESH */
}
else {
makeDerivedMesh(scene, ob, NULL, scene->customdata_mask, 0);
}
#else /* ensure CD_MASK_BAREMESH for now */
EditMesh *em = (ob == scene->obedit)? BKE_mesh_get_editmesh(ob->data): NULL;
BMEditMesh *em = (ob == scene->obedit)? ((Mesh*)ob->data)->edit_btmesh : NULL;
uint64_t data_mask= scene->customdata_mask | ob->customdata_mask | CD_MASK_BAREMESH;
if(em) {
makeDerivedMesh(scene, ob, em, data_mask); /* was CD_MASK_BAREMESH */
BKE_mesh_end_editmesh(ob->data, em);
} else
makeDerivedMesh(scene, ob, NULL, data_mask);
makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
}
else {
makeDerivedMesh(scene, ob, NULL, data_mask, 0);
}
#endif
}

@ -774,6 +774,8 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
psys->renderdata= NULL;
}
/* BMESH_TODO, for orig face data, we need to use MPoly */
int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
{
DerivedMesh *dm= ctx->dm;
@ -801,10 +803,10 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
return tot;
mvert= dm->getVertArray(dm);
mface= dm->getFaceArray(dm);
origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
totface= dm->getNumFaces(dm);
totorigface= me->totface;
mface= dm->getTessFaceArray(dm);
origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
totface= dm->getNumTessFaces(dm);
totorigface= me->totpoly;
if(totface == 0 || totorigface == 0)
return tot;
@ -1574,7 +1576,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int
case PART_FROM_FACE:
case PART_FROM_VOLUME:
{
MFace *mf=dm->getFaceData(dm,index,CD_MFACE);
MFace *mf=dm->getTessFaceData(dm,index,CD_MFACE);
return interpolate_particle_value(values[mf->v1],values[mf->v2],values[mf->v3],values[mf->v4],fw,mf->v4);
}
@ -1616,17 +1618,17 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node)
{
Mesh *me= (Mesh*)ob->data;
MFace *mface;
MPoly *mface;
OrigSpaceFace *osface;
int *origindex;
int quad, findex, totface;
float uv[2], (*faceuv)[2];
mface = dm->getFaceDataArray(dm, CD_MFACE);
origindex = dm->getFaceDataArray(dm, CD_ORIGINDEX);
osface = dm->getFaceDataArray(dm, CD_ORIGSPACE);
mface = dm->getPolyArray(dm);
origindex = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
totface = dm->getNumFaces(dm);
totface = dm->getNumTessFaces(dm);
if(osface==NULL || origindex==NULL) {
/* Assume we dont need osface data */
@ -1638,7 +1640,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
return DMCACHE_NOTFOUND;
}
}
else if(index >= me->totface)
else if(index >= me->totpoly)
return DMCACHE_NOTFOUND; /* index not in the original mesh */
psys_w_to_origspace(fw, uv);
@ -1647,7 +1649,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
for(;node; node=node->next) {
findex= GET_INT_FROM_POINTER(node->link);
faceuv= osface[findex].uv;
quad= mface[findex].v4;
quad = (mface[findex].totloop == 4);
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
@ -1663,7 +1665,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
for(findex=0; findex<totface; findex++) {
if(origindex[findex] == index) {
faceuv= osface[findex].uv;
quad= mface[findex].v4;
quad = (mface[findex].totloop == 4);
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
@ -1695,7 +1697,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
*mapindex = index;
}
else { /* FROM_FACE/FROM_VOLUME */
if(index >= dm->getNumFaces(dm))
if(index >= dm->getNumTessFaces(dm))
return 0;
*mapindex = index;
@ -1719,15 +1721,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
i = index_dmcache;
if(i== DMCACHE_NOTFOUND || i >= dm->getNumFaces(dm))
if(i== DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm))
return 0;
*mapindex = i;
/* modify the original weights to become
* weights for the derived mesh face */
osface= dm->getFaceDataArray(dm, CD_ORIGSPACE);
mface= dm->getFaceData(dm, i, CD_MFACE);
osface= dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
mface= dm->getTessFaceData(dm, i, CD_MFACE);
if(osface == NULL)
mapfw[0]= mapfw[1]= mapfw[2]= mapfw[3]= 0.0f;
@ -1785,7 +1787,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
MTFace *mtface;
MVert *mvert;
mface=dm->getFaceData(dm,mapindex,CD_MFACE);
mface=dm->getTessFaceData(dm,mapindex,CD_MFACE);
mvert=dm->getVertDataArray(dm,CD_MVERT);
mtface=CustomData_get_layer(&dm->faceData,CD_MTFACE);
@ -2935,6 +2937,11 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
DM_ensure_tessface(psmd->dm);
}
/*---first main loop: create all actual particles' paths---*/
LOOP_SHOWN_PARTICLES {
if(!psys->totchild) {
@ -3358,10 +3365,10 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
if (i==-1 || i >= dm->getNumFaces(dm)) { unit_m4(mat); return; }
if (i==-1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
mface=dm->getFaceData(dm,i,CD_MFACE);
osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
mface=dm->getTessFaceData(dm,i,CD_MFACE);
osface=dm->getTessFaceData(dm,i,CD_ORIGSPACE);
if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
@ -3676,7 +3683,6 @@ void make_local_particlesettings(ParticleSettings *part)
}
else if(is_local && is_lib) {
ParticleSettings *part_new= psys_copy_settings(part);
part_new->id.us= 0;
/* Remap paths of new ID using old library as base. */
@ -3716,7 +3722,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
if(pa) {
i= (pa->num_dmcache==DMCACHE_NOTFOUND)? pa->num: pa->num_dmcache;
if(i >= dm->getNumFaces(dm))
if(i >= dm->getNumTessFaces(dm))
i = -1;
}
else
@ -3728,7 +3734,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
texco[2]= 0.0f;
}
else {
mf= dm->getFaceData(dm, i, CD_MFACE);
mf= dm->getTessFaceData(dm, i, CD_MFACE);
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@ -4396,7 +4402,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, Partic
if(part->childtype == PART_CHILD_FACES) {
mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
if(mtface) {
mface= psmd->dm->getFaceData(psmd->dm, cpa->num, CD_MFACE);
mface= psmd->dm->getTessFaceData(psmd->dm, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
@ -4416,14 +4422,14 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, Partic
if(num == DMCACHE_NOTFOUND)
num= pa->num;
if (num >= psmd->dm->getNumFaces(psmd->dm)) {
if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num= DMCACHE_NOTFOUND;
}
if(mtface && num != DMCACHE_NOTFOUND) {
mface= psmd->dm->getFaceData(psmd->dm, num, CD_MFACE);
mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}

@ -352,9 +352,9 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
origindex= dm->getVertDataArray(dm, CD_ORIGINDEX);
}
else { /* FROM_FACE/FROM_VOLUME */
totdmelem= dm->getNumFaces(dm);
totelem= me->totface;
origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
totdmelem= dm->getNumTessFaces(dm);
totelem= me->totpoly;
origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
@ -523,8 +523,8 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
totface=dm->getNumFaces(dm);
mface_array= dm->getFaceDataArray(dm,CD_MFACE);
totface=dm->getNumTessFaces(dm);
mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
for(a=0; a<amax; a++){
if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; }
@ -783,7 +783,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
MFace *mface;
pa->num = i = ctx->index[p];
mface = dm->getFaceData(dm,i,CD_MFACE);
mface = dm->getTessFaceData(dm,i,CD_MFACE);
switch(distr){
case PART_DISTR_JIT:
@ -813,7 +813,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
if(from==PART_FROM_VOLUME){
MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
tot=dm->getNumFaces(dm);
tot=dm->getNumTessFaces(dm);
psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
@ -825,7 +825,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
min_d=2.0;
intersect=0;
for(i=0,mface=dm->getFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
for(i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
if(i==pa->num) continue;
v1=mvert[mface->v1].co;
@ -873,7 +873,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
return;
}
mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE);
mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
randu= rng_getFloat(thread->rng);
randv= rng_getFloat(thread->rng);
@ -1040,7 +1040,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
if(totpart==0)
return 0;
if (!finaldm->deformedOnly && !finaldm->getFaceDataArray(finaldm, CD_ORIGINDEX)) {
if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
return 0;
@ -1071,6 +1071,10 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
distr=PART_DISTR_RAND;
BLI_srandom(31415926 + psys->seed + psys->child_seed);
dm= finaldm;
/* BMESH ONLY */
DM_ensure_tessface(dm);
children=1;
tree=BLI_kdtree_new(totpart);
@ -1092,6 +1096,11 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
dm= CDDM_from_mesh((Mesh*)ob->data, ob);
/* BMESH ONLY, for verts we dont care about tessfaces */
if (from != PART_FROM_VERT) {
DM_ensure_tessface(dm);
}
/* we need orco for consistent distributions */
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, get_mesh_orco_verts(ob));
@ -1117,7 +1126,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
}
/* Get total number of emission elements and allocate needed arrays */
totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumFaces(dm);
totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
if(totelem == 0){
distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
@ -1146,7 +1155,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
orcodata= dm->getVertDataArray(dm, CD_ORCO);
for(i=0; i<totelem; i++){
MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
if(orcodata) {
copy_v3_v3(co1, orcodata[mf->v1]);
@ -1204,7 +1213,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for(i=0;i<totelem; i++){
MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if(mf->v4) {
@ -1278,8 +1287,8 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
COMPARE_ORIG_INDEX= dm->getVertDataArray(dm, CD_ORIGINDEX);
}
else {
if(dm->numFaceData)
COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
if(dm->numTessFaceData)
COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
if(COMPARE_ORIG_INDEX) {
@ -3516,7 +3525,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
if(!dm) {
dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0);
dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0, 0, 0);
DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
}
@ -3551,7 +3560,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if(dvert) {
if(!dvert->totweight) {
dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight");
dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
dvert->totweight = 1;
}
@ -3572,7 +3581,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if(dvert) {
if(!dvert->totweight) {
dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight");
dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
dvert->totweight = 1;
}
/* roots should be 1.0, the rest can be anything from 0.0 to 1.0 */

@ -1697,7 +1697,7 @@ float hyp3,hyp4,b4,b5
hyp2 = fabsf(angle*x+y+(-(yo-posy*0.5f)-angle*(xo-posx*0.5f)))*wipezone->pythangle;
}
hwidth= MIN2(hwidth, fabsf(b3-b1)/2.0f);
hwidth = minf(hwidth, fabsf(b3-b1)/2.0f);
if(b2 < b1 && b2 < b3 ){
output = in_band(hwidth,hyp,0,1);

@ -54,6 +54,8 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
#include "BKE_mesh.h"
#include "BKE_tessmesh.h"
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
@ -89,11 +91,10 @@ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *c
DerivedMesh *object_get_derived_final(Object *ob)
{
Mesh *me= ob->data;
EditMesh *em = BKE_mesh_get_editmesh(me);
BMEditMesh *em = me->edit_btmesh;
if(em) {
DerivedMesh *dm = em->derivedFinal;
BKE_mesh_end_editmesh(me, em);
return dm;
}

@ -317,7 +317,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
if(!smd->coll->bvhtree)
{
smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
}
return 1;
}
@ -328,7 +328,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
{
MVert *mvert = dm->getVertArray(dm);
MFace *mface = dm->getFaceArray(dm);
MFace *mface = dm->getTessFaceArray(dm);
int i = 0, divs = 0;
int *tridivs = NULL;
float cell_len = 1.0 / 50.0; // for res = 50
@ -336,16 +336,16 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
int quads = 0, facecounter = 0;
// count quads
for(i = 0; i < dm->getNumFaces(dm); i++)
for(i = 0; i < dm->getNumTessFaces(dm); i++)
{
if(mface[i].v4)
quads++;
}
calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), dm->getNumTessFaces(dm) + quads, &tridivs, cell_len);
// count triangle divisions
for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
{
divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
}
@ -362,7 +362,7 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
copy_v3_v3(&scs->points[i * 3], tmpvec);
}
for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
{
int again = 0;
do
@ -1008,6 +1008,7 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
{
ParticleSimulationData sim;
ParticleSystem *psys = sfs->psys;
int totpart=psys->totpart, totchild;
int p = 0;
float *density = smoke_get_density(sds->fluid);
float *bigdensity = smoke_turbulence_get_density(sds->wt);
@ -1043,7 +1044,23 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
}
// mostly copied from particle code
for(p=0; p<psys->totpart; p++)
if(psys->part->type==PART_HAIR)
{
/*
if(psys->childcache)
{
totchild = psys->totchildcache;
}
else
*/
// TODO: PART_HAIR not supported whatsoever
totchild=0;
}
else
totchild=psys->totchild*psys->part->disp/100;
for(p=0; p<totpart+totchild; p++)
{
int cell[3];
size_t i = 0;
@ -1051,17 +1068,27 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
int badcell = 0;
ParticleKey state;
if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
continue;
if(p < totpart)
{
if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
continue;
}
else
{
/* handle child particle */
ChildParticle *cpa = &psys->child[p - totpart];
if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
continue;
}
state.time = smd->time;
if(psys_get_particle_state(&sim, p, &state, 0) == 0)
continue;
// copy_v3_v3(pos, pa->state.co);
// mul_m4_v3(ob->imat, pos);
// 1. get corresponding cell
// mul_m4_v3(ob->imat, pos);
// 1. get corresponding cell
get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, state.co, cell, 0);
// check if cell is valid (in the domain boundary)
for(i = 0; i < 3; i++)
@ -1354,7 +1381,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
if(smd->coll->dm)
smd->coll->dm->release(smd->coll->dm);
smd->coll->dm = CDDM_copy(dm);
smd->coll->dm = CDDM_copy_from_tessface(dm);
#endif
// rigid movement support

File diff suppressed because it is too large Load Diff

@ -177,11 +177,11 @@
* same purpose as BLI_array_staticdeclare()
* but use when the max size is known ahead of time */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
char _##arr##_static[maxstatic*sizeof(*arr)]; \
char _##arr##_static[maxstatic*sizeof(*(arr))]; \
const int _##arr##_is_static= ((void *)_##arr##_static) != ( \
arr= (realsize <= maxstatic) ? \
arr= ((realsize) <= maxstatic) ? \
(void *)_##arr##_static : \
MEM_mallocN(sizeof(*arr)*realsize, allocstr) \
MEM_mallocN(sizeof(*(arr)) * (realsize), allocstr) \
) \
#define BLI_array_fixedstack_free(arr) \

@ -51,6 +51,12 @@ extern "C" {
/* scanfill.c: used in displist only... */
struct EditVert *BLI_addfillvert(float *vec);
struct EditEdge *BLI_addfilledge(struct EditVert *v1, struct EditVert *v2);
/* Optionally set EditEdge f to this to mark original boundary edges.
Only needed if there are internal diagonal edges pased to BLI_edgefill. */
#define FILLBOUNDARY 1
int BLI_begin_edgefill(void);
int BLI_edgefill(short mat_nr);
void BLI_end_edgefill(void);

@ -0,0 +1,73 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BLI_SMALLHASH_H__
#define __BLI_SMALLHASH_H__
/** \file BLI_smallhash.h
* \ingroup bli
*/
/* a light stack-friendly hash library,
* (it uses stack space for smallish hash tables) */
/* based on a doubling non-chaining approach */
typedef struct {
uintptr_t key;
void *val;
} SmallHashEntry;
/*how much stack space to use before dynamically allocating memory*/
#define SMSTACKSIZE 521
typedef struct SmallHash {
SmallHashEntry *table;
SmallHashEntry _stacktable[SMSTACKSIZE];
SmallHashEntry _copytable[SMSTACKSIZE];
SmallHashEntry *stacktable, *copytable;
int used;
int curhash;
int size;
} SmallHash;
typedef struct {
SmallHash *hash;
int i;
} SmallHashIter;
void BLI_smallhash_init(SmallHash *hash);
void BLI_smallhash_release(SmallHash *hash);
void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item);
void BLI_smallhash_remove(SmallHash *hash, uintptr_t key);
void * BLI_smallhash_lookup(SmallHash *hash, uintptr_t key);
int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key);
int BLI_smallhash_count(SmallHash *hash);
void * BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key);
void * BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key);
/* void BLI_smallhash_print(SmallHash *hash); */ /* UNUSED */
#endif /* __BLI_SMALLHASH_H__ */

@ -0,0 +1,81 @@
#if 0
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* Contributor(s): Joseph Eagar (original author)
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BLI_SPARSEMAP_H__
#define __BLI_SPARSEMAP_H__
/** \file BLI_sparsemap.h
* \ingroup bli
*/
#include "BLI_math_inline.h"
typedef struct SparseMap {
int max;
int blocksize;
void **blocks;
int totblock;
} SparseMap;
MALWAYS_INLINE SparseMap *BLI_sparsemap_new(int blocksize, char *name)
{
SparseMap *sm = MEM_callocN(sizeof(SparseMap), name);
sm->blocksize = blocksize;
return sm;
}
MALWAYS_INLINE void BLI_sparsemap_free(SparseMap *sm)
{
if (sm->blocks)
MEM_freeN(sm->blocks);
MEM_freeN(sm);
}
MALWAYS_INLINE void BLI_sparsemap_set(SparseMap *sm, int index, void *ptr)
{
if (index >= sm->max || (sm->blocks && !sm->blocks[index/sm->blocksize])) {
int totblock = MAX2((index+1)/sm->blocksize, 2);
void *blocks = MEM_callocN(sizeof(void*)*totblock);
if (sm->blocks)
memcpy(blocks, sm->blocks, sizeof(void*)*sm->totblock);
sm->totblock = totblock;
MEM_freeN(sm->blocks);
sm->blocks = blocks;
}
if (!sm->blocks[index/sm->blocksize]) {
sm->blocks[index/sm->blocksize] = MEM_mallocN(sizeof(void*)*sm->blocksize);
}
sm->blocks[index/sm->blocksize] = ptr;
}
#endif /* __BLI_SPARSEMAP_H__ */
#endif

@ -76,6 +76,7 @@ int BLI_system_thread_count(void); /* gets the number of threads the system can
#define LOCK_OPENGL 5
#define LOCK_NODES 6
#define LOCK_MOVIECLIP 7
#define LOCK_SCANFILL 8
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);

@ -80,6 +80,7 @@ set(SRC
intern/rand.c
intern/rct.c
intern/scanfill.c
intern/smallhash.c
intern/storage.c
intern/string.c
intern/string_utf8.c
@ -90,6 +91,8 @@ set(SRC
intern/winstuff.c
BLI_array.h
BLI_smallhash.h
BLI_sparsemap.h
BLI_args.h
BLI_blenlib.h
BLI_boxpack2d.h

@ -5,6 +5,8 @@ sources = env.Glob('intern/*.c')
cflags=''
incs = '. ../makesdna ../blenkernel #/intern/guardedalloc #/intern/ghost ../editors/include ../gpu ../blenloader'
incs += ' ../windowmanager ../bmesh #/extern/glew/include'
incs += ' ' + env['BF_FREETYPE_INC']
incs += ' ' + env['BF_ZLIB_INC']
defs = []

@ -47,7 +47,7 @@
#include "BLO_sys_types.h" // for intptr_t support
/***/
static unsigned int hashsizes[]= {
unsigned int hashsizes[]= {
5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
4194319, 8388617, 16777259, 33554467, 67108879, 134217757,

@ -1585,7 +1585,7 @@ void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
}
/* coordinates are new -- normals should also be updated */
mesh_calc_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
mesh_calc_normals_tessface(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
for (a= 0; a < pbvh->totnode; ++a)
BLI_pbvh_node_mark_update(&pbvh->nodes[a]);

@ -30,6 +30,10 @@
* \ingroup bli
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
@ -38,6 +42,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_scanfill.h"
#include "BLI_utildefines.h"
#include "BLI_threads.h"
/* callbacks for errors and interrupts and some goo */
static void (*BLI_localErrorCallBack)(const char*) = NULL;
@ -137,54 +143,64 @@ struct mem_elements {
only to be used within loops, and not by one function at a time
free in the end, with argument '-1'
*/
#define MEM_ELEM_BLOCKSIZE 16384
static struct mem_elements * melem__cur= 0;
static int melem__offs= 0; /* the current free address */
static ListBase melem__lb= {NULL, NULL};
static void *new_mem_element(int size)
static void *mem_element_new(int size)
{
int blocksize= 16384;
static int offs= 0; /* the current free address */
static struct mem_elements *cur= 0;
static ListBase lb= {0, 0};
void *adr;
BLI_assert(!(size>10000 || size==0)); /* this is invalid use! */
size = (size + 3 ) & ~3; /* allocate in units of 4 */
if(size>10000 || size==0) {
printf("incorrect use of new_mem_element\n");
if(melem__cur && (size + melem__offs < MEM_ELEM_BLOCKSIZE)) {
void *adr= (void *) (melem__cur->data+melem__offs);
melem__offs+= size;
return adr;
}
else if(size== -1) {
cur= lb.first;
while(cur) {
MEM_freeN(cur->data);
cur= cur->next;
else {
melem__cur= MEM_callocN( sizeof(struct mem_elements), "newmem");
melem__cur->data= MEM_callocN(MEM_ELEM_BLOCKSIZE, "newmem");
BLI_addtail(&melem__lb, melem__cur);
melem__offs= size;
return melem__cur->data;
}
}
static void mem_element_reset(void)
{
struct mem_elements *first;
/*BMESH_TODO: keep the first block, gives memory leak on exit with 'newmem' */
if((first= melem__lb.first)) { /* can be false if first fill fails */
BLI_remlink(&melem__lb, first);
melem__cur= melem__lb.first;
while(melem__cur) {
MEM_freeN(melem__cur->data);
melem__cur= melem__cur->next;
}
BLI_freelistN(&lb);
return NULL;
BLI_freelistN(&melem__lb);
/*reset the block we're keeping*/
BLI_addtail(&melem__lb, first);
memset(first->data, 0, MEM_ELEM_BLOCKSIZE);
}
size= 4*( (size+3)/4 );
if(cur) {
if(size+offs < blocksize) {
adr= (void *) (cur->data+offs);
offs+= size;
return adr;
}
}
cur= MEM_callocN( sizeof(struct mem_elements), "newmem");
cur->data= MEM_callocN(blocksize, "newmem");
BLI_addtail(&lb, cur);
offs= size;
return cur->data;
melem__cur= first;
melem__offs= 0;
}
void BLI_end_edgefill(void)
{
new_mem_element(-1);
mem_element_reset();
fillvertbase.first= fillvertbase.last= 0;
filledgebase.first= filledgebase.last= 0;
fillfacebase.first= fillfacebase.last= 0;
BLI_unlock_thread(LOCK_SCANFILL);
}
/* **** FILL ROUTINES *************************** */
@ -193,7 +209,7 @@ EditVert *BLI_addfillvert(float *vec)
{
EditVert *eve;
eve= new_mem_element(sizeof(EditVert));
eve= mem_element_new(sizeof(EditVert));
BLI_addtail(&fillvertbase, eve);
eve->co[0] = vec[0];
@ -207,7 +223,7 @@ EditEdge *BLI_addfilledge(EditVert *v1, EditVert *v2)
{
EditEdge *newed;
newed= new_mem_element(sizeof(EditEdge));
newed= mem_element_new(sizeof(EditEdge));
BLI_addtail(&filledgebase, newed);
newed->v1= v1;
@ -221,7 +237,7 @@ static void addfillface(EditVert *v1, EditVert *v2, EditVert *v3, short mat_nr)
/* does not make edges */
EditFace *evl;
evl= new_mem_element(sizeof(EditFace));
evl= mem_element_new(sizeof(EditFace));
BLI_addtail(&fillfacebase, evl);
evl->v1= v1;
@ -498,7 +514,7 @@ static int scanfill(PolyFill *pf, short mat_nr)
EditVert *eve,*v1,*v2,*v3;
EditEdge *eed,*nexted,*ed1,*ed2,*ed3;
float miny = 0.0;
int a,b,verts, maxface, totface;
int a,b,verts, maxface, totface;
short nr, test, twoconnected=0;
nr= pf->nr;
@ -534,7 +550,7 @@ static int scanfill(PolyFill *pf, short mat_nr)
}
else {
eed->v2->f= 255;
eed->v2->tmp.v = eed->v1->tmp.v;
eed->v2->tmp.v = eed->v1;
}
}
}
@ -564,20 +580,22 @@ static int scanfill(PolyFill *pf, short mat_nr)
eed= filledgebase.first;
while(eed) {
nexted= eed->next;
eed->f= 0;
BLI_remlink(&filledgebase,eed);
/* commented all of this out, this I have no idea for what it is for, probably from ancient past */
/* it does crash blender, since it uses mixed original and new vertices (ton) */
// if(eed->v1->f==255) {
// v1= eed->v1;
// while((eed->v1->f == 255) && (eed->v1->tmp.v != v1))
// eed->v1 = eed->v1->tmp.v;
// }
// if(eed->v2->f==255) {
// v2= eed->v2;
// while((eed->v2->f == 255) && (eed->v2->tmp.v != v2))
// eed->v2 = eed->v2->tmp.v;
// }
/* This code is for handling zero-length edges that get
collapsed in step 0. It was removed for some time to
fix trunk bug #4544, so if that comes back, this code
may need some work, or there will have to be a better
fix to #4544. */
if(eed->v1->f==255) {
v1= eed->v1;
while((eed->v1->f == 255) && (eed->v1->tmp.v != v1))
eed->v1 = eed->v1->tmp.v;
}
if(eed->v2->f==255) {
v2= eed->v2;
while((eed->v2->f == 255) && (eed->v2->tmp.v != v2))
eed->v2 = eed->v2->tmp.v;
}
if(eed->v1!=eed->v2) addedgetoscanlist(eed,verts);
eed= nexted;
@ -687,8 +705,8 @@ static int scanfill(PolyFill *pf, short mat_nr)
ed1->v2->f= 0;
ed1->v1->h--;
ed1->v2->h--;
/* ed2 can be removed when it's an old one */
if(ed2->f==0 && twoconnected) {
/* ed2 can be removed when it's a boundary edge */
if((ed2->f == 0 && twoconnected) || (ed2->f == FILLBOUNDARY)) {
BLI_remlink((ListBase *)&(sc->first),ed2);
BLI_addtail(&filledgebase,ed2);
ed2->v2->f= 0;
@ -706,19 +724,20 @@ static int scanfill(PolyFill *pf, short mat_nr)
/* printf("add new edge %x %x\n",v1,v3); */
sc1= addedgetoscanlist(ed3, verts);
if(sc1) { /* ed3 already exists: remove */
if(sc1) { /* ed3 already exists: remove if a boundary */
/* printf("Edge exists\n"); */
ed3->v1->h--;
ed3->v2->h--;
if(twoconnected) ed3= sc1->first;
else ed3= 0;
ed3= sc1->first;
while(ed3) {
if( (ed3->v1==v1 && ed3->v2==v3) || (ed3->v1==v3 && ed3->v2==v1) ) {
BLI_remlink((ListBase *)&(sc1->first),ed3);
BLI_addtail(&filledgebase,ed3);
ed3->v1->h--;
ed3->v2->h--;
if (twoconnected || ed3->f==FILLBOUNDARY) {
BLI_remlink((ListBase *)&(sc1->first),ed3);
BLI_addtail(&filledgebase,ed3);
ed3->v1->h--;
ed3->v2->h--;
}
break;
}
ed3= ed3->next;
@ -750,6 +769,12 @@ static int scanfill(PolyFill *pf, short mat_nr)
}
int BLI_begin_edgefill(void)
{
BLI_lock_thread(LOCK_SCANFILL);
return 1;
}
int BLI_edgefill(short mat_nr)
{
@ -765,24 +790,55 @@ int BLI_edgefill(short mat_nr)
EditVert *eve;
EditEdge *eed,*nexted;
PolyFill *pflist,*pf;
float *minp, *maxp, *v1, *v2, norm[3], len;
float limit, *minp, *maxp, *v1, *v2, norm[3], len;
short a,c,poly=0,ok=0,toggle=0;
int totfaces= 0; /* total faces added */
/* reset variables */
eve= fillvertbase.first;
a = 0;
while(eve) {
eve->f= 0;
eve->xs= 0;
eve->h= 0;
eve= eve->next;
a += 1;
}
if (a == 3 && (mat_nr & 2)) {
eve = fillvertbase.first;
addfillface(eve, eve->next, eve->next->next, 0);
return 1;
} else if (a == 4 && (mat_nr & 2)) {
float vec1[3], vec2[3];
eve = fillvertbase.first;
/* no need to check 'eve->next->next->next' is valid, already counted */
if (1) { //BMESH_TODO) {
/*use shortest diagonal for quad*/
sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);
if (INPR(vec1, vec1) < INPR(vec2, vec2)) {
addfillface(eve, eve->next, eve->next->next, 0);
addfillface(eve->next->next, eve->next->next->next, eve, 0);
} else{
addfillface(eve->next, eve->next->next, eve->next->next->next, 0);
addfillface(eve->next->next->next, eve, eve->next, 0);
}
} else {
addfillface(eve, eve->next, eve->next->next, 0);
addfillface(eve->next->next, eve->next->next->next, eve, 0);
}
return 2;
}
/* first test vertices if they are in edges */
/* including resetting of flags */
eed= filledgebase.first;
while(eed) {
eed->f= eed->f1= eed->h= 0;
eed->f1= eed->h= 0;
eed->v1->f= 1;
eed->v2->f= 1;
@ -810,9 +866,17 @@ int BLI_edgefill(short mat_nr)
v1= eve->co;
v2= 0;
eve= fillvertbase.first;
limit = a < 5 ? FLT_EPSILON*200 : M_PI/24.0;
while(eve) {
if(v2) {
if( compare_v3v3(v2, eve->co, COMPLIMIT)==0) {
float inner = angle_v3v3v3(v1, v2, eve->co);
if (fabsf(inner-M_PI) < limit || fabsf(inner) < limit) {
eve = eve->next;
continue;
}
len= normal_tri_v3( norm,v1, v2, eve->co);
if(len != 0.0f) break;
}
@ -922,7 +986,7 @@ int BLI_edgefill(short mat_nr)
- eve->h :amount of edges connected to vertex
- eve->tmp.v :store! original vertex number
- eed->f :
- eed->f :1= boundary edge (optionally set by caller)
- eed->f1 :poly number
*/

@ -0,0 +1,281 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_smallhash.h"
/* SMHASH_CELL_UNUSED means this cell is inside a key series,
* while SMHASH_CELL_FREE means this cell terminates a key series.
*
* no chance of anyone shoving INT32_MAX-2 into a *val pointer, I
* imagine. hopefully.
*
* note: these have the SMHASH suffix because we may want to make them public.
*/
#define SMHASH_CELL_UNUSED ((void *)0x7FFFFFFF)
#define SMHASH_CELL_FREE ((void *)0x7FFFFFFD)
#define SMHASH_NONZERO(n) ((n) + !(n))
#define SMHASH_NEXT(h, hoff) ABS(((h) + ((hoff = SMHASH_NONZERO(hoff * 2) + 1), hoff)))
extern unsigned int hashsizes[];
void BLI_smallhash_init(SmallHash *hash)
{
int i;
memset(hash, 0, sizeof(*hash));
hash->table = hash->_stacktable;
hash->curhash = 2;
hash->size = hashsizes[hash->curhash];
hash->copytable = hash->_copytable;
hash->stacktable = hash->_stacktable;
for (i = 0; i < hash->size; i++) {
hash->table[i].val = SMHASH_CELL_FREE;
}
}
/*NOTE: does *not* free *hash itself! only the direct data!*/
void BLI_smallhash_release(SmallHash *hash)
{
if (hash == NULL) {
return;
}
if (hash->table != hash->stacktable) {
MEM_freeN(hash->table);
}
}
void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item)
{
int h, hoff=1;
if (hash->size < hash->used * 3) {
int newsize = hashsizes[++hash->curhash];
SmallHashEntry *tmp;
int i = 0;
if (hash->table != hash->stacktable || newsize > SMSTACKSIZE) {
tmp = MEM_callocN(sizeof(*hash->table) * newsize, __func__);
}
else {
SWAP(SmallHashEntry *, hash->stacktable, hash->copytable);
tmp = hash->stacktable;
}
SWAP(SmallHashEntry *, tmp, hash->table);
hash->size = newsize;
for (i = 0; i < hash->size; i++) {
hash->table[i].val = SMHASH_CELL_FREE;
}
for (i = 0; i<hashsizes[hash->curhash - 1]; i++) {
if (ELEM(tmp[i].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
continue;
}
h = ABS((int)(tmp[i].key));
hoff = 1;
while (!ELEM(hash->table[h % newsize].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
h = SMHASH_NEXT(h, hoff);
}
h %= newsize;
hash->table[h].key = tmp[i].key;
hash->table[h].val = tmp[i].val;
}
if (tmp != hash->stacktable && tmp != hash->copytable) {
MEM_freeN(tmp);
}
}
h = ABS((int)key);
hoff = 1;
while (!ELEM(hash->table[h % hash->size].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
h = SMHASH_NEXT(h, hoff);
}
h %= hash->size;
hash->table[h].key = key;
hash->table[h].val = item;
hash->used++;
}
void BLI_smallhash_remove(SmallHash *hash, uintptr_t key)
{
int h, hoff=1;
h = ABS((int)key);
while ((hash->table[h % hash->size].key != key) ||
(hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
{
if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
return;
}
h = SMHASH_NEXT(h, hoff);
}
h %= hash->size;
hash->table[h].key = 0;
hash->table[h].val = SMHASH_CELL_UNUSED;
}
void *BLI_smallhash_lookup(SmallHash *hash, uintptr_t key)
{
int h, hoff=1;
void *v;
h = ABS((int)key);
if (hash->table == NULL) {
return NULL;
}
while ((hash->table[h % hash->size].key != key) ||
(hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
{
if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
return NULL;
}
h = SMHASH_NEXT(h, hoff);
}
v = hash->table[h % hash->size].val;
if (ELEM(v, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
return NULL;
}
return v;
}
int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key)
{
int h = ABS((int)key);
int hoff =1;
if (hash->table == NULL) {
return 0;
}
while ((hash->table[h % hash->size].key != key) ||
(hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
{
if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
return 0;
}
h = SMHASH_NEXT(h, hoff);
}
return !ELEM(hash->table[h % hash->size].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE);
}
int BLI_smallhash_count(SmallHash *hash)
{
return hash->used;
}
void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
{
while (iter->i < iter->hash->size) {
if ( (iter->hash->table[iter->i].val != SMHASH_CELL_UNUSED) &&
(iter->hash->table[iter->i].val != SMHASH_CELL_FREE))
{
if (key) {
*key = iter->hash->table[iter->i].key;
}
iter->i++;
return iter->hash->table[iter->i - 1].val;
}
iter->i++;
}
return NULL;
}
void *BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key)
{
iter->hash = hash;
iter->i = 0;
return BLI_smallhash_iternext(iter, key);
}
/* note, this was called _print_smhash in knifetool.c
* it may not be intended for general use - campbell */
#if 0
void BLI_smallhash_print(SmallHash *hash)
{
int i, linecol=79, c=0;
printf("{");
for (i=0; i<hash->size; i++) {
if (hash->table[i].val == SMHASH_CELL_UNUSED) {
printf("--u-");
}
else if (hash->table[i].val == SMHASH_CELL_FREE) {
printf("--f-");
}
else {
printf("%2x", (unsigned int)hash->table[i].key);
}
if (i != hash->size-1)
printf(", ");
c += 6;
if (c >= linecol) {
printf("\n ");
c = 0;
}
}
fflush(stdout);
}
#endif

@ -115,6 +115,7 @@ static pthread_mutex_t _rcache_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _opengl_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _scanfill_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
static int thread_levels= 0; /* threads can be invoked inside threads */
@ -353,6 +354,8 @@ void BLI_lock_thread(int type)
pthread_mutex_lock(&_nodes_lock);
else if (type==LOCK_MOVIECLIP)
pthread_mutex_lock(&_movieclip_lock);
else if (type == LOCK_SCANFILL)
pthread_mutex_lock(&_scanfill_lock);
}
void BLI_unlock_thread(int type)
@ -373,6 +376,8 @@ void BLI_unlock_thread(int type)
pthread_mutex_unlock(&_nodes_lock);
else if(type==LOCK_MOVIECLIP)
pthread_mutex_unlock(&_movieclip_lock);
else if(type == LOCK_SCANFILL)
pthread_mutex_unlock(&_scanfill_lock);
}
/* Mutex Locks */

@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c')
incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
incs += ' ../makesdna ../editors/include'
incs += ' ../render/extern/include ../makesrna ../nodes ../imbuf'
incs += ' ../render/extern/include ../makesrna ../nodes ../bmesh ../imbuf'
incs += ' ' + env['BF_ZLIB_INC']

@ -101,6 +101,7 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BKE_anim.h"
#include "BKE_action.h"
@ -2704,6 +2705,16 @@ static void lib_link_key(FileData *fd, Main *main)
key= main->key.first;
while(key) {
/*check if we need to generate unique ids for the shapekeys*/
if (!key->uidgen) {
KeyBlock *block;
key->uidgen = 1;
for (block=key->block.first; block; block=block->next) {
block->uid = key->uidgen++;
}
}
if(key->id.flag & LIB_NEEDLINK) {
if(key->adt) lib_link_animdata(fd, &key->id, key->adt);
@ -3626,6 +3637,26 @@ static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata
}
static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
{
int i;
for(i=0; i<pdata->totlayer; i++) {
CustomDataLayer *layer = &pdata->layers[i];
if(layer->type == CD_MTEXPOLY) {
MTexPoly *tf= layer->data;
int i;
for (i=0; i<totface; i++, tf++) {
tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
if(tf->tpage && tf->tpage->id.us==0)
tf->tpage->id.us= 1;
}
}
}
}
static void lib_link_mesh(FileData *fd, Main *main)
{
Mesh *me;
@ -3653,10 +3684,28 @@ static void lib_link_mesh(FileData *fd, Main *main)
me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
if(me->mr && me->mr->levels.first)
lib_link_customdata_mtface(fd, me, &me->mr->fdata,
((MultiresLevel*)me->mr->levels.first)->totface);
/*check if we need to convert mfaces to mpolys*/
if (me->totface && !me->totpoly) {
convert_mfaces_to_mpolys(me);
}
/*
* Re-tesselate, even if the polys were just created from tessfaces, this
* is important because it:
* - fill the CD_POLYINDEX layer
* - gives consistency of tessface between loading from a file and
* converting an edited BMesh back into a mesh (i.e. it replaces
* quad tessfaces in a loaded mesh immediately, instead of lazily
* waiting until edit mode has been entered/exited, making it easier
* to recognize problems that would otherwise only show up after edits).
*/
BKE_mesh_tessface_calc(me);
me->id.flag -= LIB_NEEDLINK;
}
me= me->id.next;
@ -3675,10 +3724,17 @@ static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
}
for (i= count; i > 0; i--, mdverts++) {
if(mdverts->dw) {
mdverts->dw= newdataadr(fd, mdverts->dw);
/*convert to vgroup allocation system*/
MDeformWeight *dw;
if(mdverts->dw && (dw= newdataadr(fd, mdverts->dw))) {
const ssize_t dw_len= mdverts->totweight * sizeof(MDeformWeight);
void *dw_tmp= MEM_mallocN(dw_len, "direct_link_dverts");
memcpy(dw_tmp, dw, dw_len);
mdverts->dw= dw_tmp;
MEM_freeN(dw);
}
if (mdverts->dw == NULL) {
else {
mdverts->dw= NULL;
mdverts->totweight= 0;
}
}
@ -3691,7 +3747,18 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
for(i = 0; i < count; ++i) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
/*put .disps into cellalloc system*/
if (mdisps[i].disps) {
float *disp2;
disp2 = MEM_mallocN(MEM_allocN_len(mdisps[i].disps), "cellalloc .disps copy");
memcpy(disp2, mdisps[i].disps, MEM_allocN_len(mdisps[i].disps));
MEM_freeN(mdisps[i].disps);
mdisps[i].disps = (float (*)[3])disp2;
}
if( (fd->flags & FD_FLAGS_SWITCH_ENDIAN) && (mdisps[i].disps) ) {
/* DNA_struct_switch_endian doesn't do endian swap for (*disps)[] */
/* this does swap for data written at write_mdisps() - readfile.c */
@ -3741,12 +3808,17 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->mvert= newdataadr(fd, mesh->mvert);
mesh->medge= newdataadr(fd, mesh->medge);
mesh->mface= newdataadr(fd, mesh->mface);
mesh->mloop= newdataadr(fd, mesh->mloop);
mesh->mpoly= newdataadr(fd, mesh->mpoly);
mesh->tface= newdataadr(fd, mesh->tface);
mesh->mtface= newdataadr(fd, mesh->mtface);
mesh->mcol= newdataadr(fd, mesh->mcol);
mesh->msticky= newdataadr(fd, mesh->msticky);
mesh->dvert= newdataadr(fd, mesh->dvert);
mesh->mloopcol= newdataadr(fd, mesh->mloopcol);
mesh->mloopuv= newdataadr(fd, mesh->mloopuv);
mesh->mtpoly= newdataadr(fd, mesh->mtpoly);
/* animdata */
mesh->adt= newdataadr(fd, mesh->adt);
direct_link_animdata(fd, mesh->adt);
@ -3758,7 +3830,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->vdata, mesh->totvert);
direct_link_customdata(fd, &mesh->edata, mesh->totedge);
direct_link_customdata(fd, &mesh->fdata, mesh->totface);
direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
#ifdef USE_BMESH_FORWARD_COMPAT
/* NEVER ENABLE THIS CODE INTO BMESH!
@ -3791,7 +3865,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->bb= NULL;
mesh->mselect = NULL;
mesh->edit_mesh= NULL;
mesh->edit_btmesh= NULL;
/* Multires data */
mesh->mr= newdataadr(fd, mesh->mr);
@ -6795,7 +6869,7 @@ static void customdata_version_242(Mesh *me)
}
}
mesh_update_customdata_pointers(me);
mesh_update_customdata_pointers(me, TRUE);
}
/*only copy render texface layer from active*/
@ -12498,7 +12572,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Mesh *me;
for(me= main->mesh.first; me; me= me->id.next)
mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL);
}
if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)){

@ -156,6 +156,7 @@ Any case: direct data is ALWAYS after the lib block
#include "BKE_modifier.h"
#include "BKE_fcurve.h"
#include "BKE_pointcache.h"
#include "BKE_mesh.h"
#include "BLO_writefile.h"
#include "BLO_readfile.h"
@ -1686,22 +1687,135 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
static void write_meshs(WriteData *wd, ListBase *idbase)
{
Mesh *mesh;
int save_for_old_blender= 0;
#ifdef USE_BMESH_SAVE_AS_COMPAT
save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
#endif
mesh= idbase->first;
while(mesh) {
if(mesh->id.us>0 || wd->current) {
/* write LibData */
writestruct(wd, ID_ME, "Mesh", 1, mesh);
if (!save_for_old_blender) {
/* direct data */
if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
if (mesh->adt) write_animdata(wd, mesh->adt);
#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
Mesh backup_mesh = {{0}};
/* cache only - dont write */
backup_mesh.mface = mesh->mface;
mesh->mface = NULL;
/* -- */
backup_mesh.totface = mesh->totface;
mesh->totface = 0;
/* -- */
#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
writestruct(wd, ID_ME, "Mesh", 1, mesh);
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
/* direct data */
if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
if (mesh->adt) write_animdata(wd, mesh->adt);
writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
/* fdata is really a dummy - written so slots align */
write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
/* cache only - dont write */
mesh->mface = backup_mesh.mface;
/* -- */
mesh->totface = backup_mesh.totface;
#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
}
else {
#ifdef USE_BMESH_SAVE_AS_COMPAT
Mesh backup_mesh = {{0}};
/* backup */
backup_mesh.mpoly = mesh->mpoly;
mesh->mpoly = NULL;
/* -- */
backup_mesh.mface = mesh->mface;
mesh->mface = NULL;
/* -- */
backup_mesh.totface = mesh->totface;
mesh->totface = 0;
/* -- */
backup_mesh.totpoly = mesh->totpoly;
mesh->totpoly = 0;
/* -- */
backup_mesh.totloop = mesh->totloop;
mesh->totloop = 0;
/* -- */
backup_mesh.fdata = mesh->fdata;
memset(&mesh->fdata, 0, sizeof(CustomData));
/* -- */
backup_mesh.pdata = mesh->pdata;
memset(&mesh->pdata, 0, sizeof(CustomData));
/* -- */
backup_mesh.ldata = mesh->ldata;
memset(&mesh->ldata, 0, sizeof(CustomData));
/* -- */
backup_mesh.edit_btmesh = mesh->edit_btmesh;
mesh->edit_btmesh = NULL;
/* backup */
/* now fill in polys to mfaces*/
mesh->totface= mesh_mpoly_to_mface(&mesh->fdata, &backup_mesh.ldata, &backup_mesh.pdata,
mesh->totface, backup_mesh.totloop, backup_mesh.totpoly);
mesh_update_customdata_pointers(mesh, FALSE);
writestruct(wd, ID_ME, "Mesh", 1, mesh);
/* direct data */
if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
if (mesh->adt) write_animdata(wd, mesh->adt);
writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
/* harmless for older blender versioins but _not_ writing these keeps file size down */
/*
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
*/
/* restore */
mesh->mpoly = backup_mesh.mpoly;
/* -- */
mesh->mface = backup_mesh.mface;
/* -- */
CustomData_free(&mesh->fdata, mesh->totface);
/* -- */
mesh->fdata= backup_mesh.fdata;
/* -- */
mesh->pdata= backup_mesh.pdata;
/* -- */
mesh->ldata= backup_mesh.ldata;
/* -- */
mesh->totface = backup_mesh.totface;
mesh->totpoly = backup_mesh.totpoly;
mesh->totloop = backup_mesh.totloop;
/* -- */
mesh_update_customdata_pointers(mesh, FALSE);
/* --*/
mesh->edit_btmesh = backup_mesh.edit_btmesh; /* keep this after updating custom pointers */
/* restore */
#endif /* USE_BMESH_SAVE_AS_COMPAT */
}
}
mesh= mesh->id.next;
}

@ -7,6 +7,8 @@ incs = '. .. #/intern/guardedalloc ../blenlib ../imbuf ../makesdna ../blenloader
defs = []
incs += ' ' + env["BF_PTHREADS_INC"]
if env['WITH_BF_QUICKTIME']:
defs.append('WITH_QUICKTIME')
incs += ' ' + env['BF_QUICKTIME_INC']

@ -0,0 +1,137 @@
# $Id: CMakeLists.txt 31746 2010-09-04 05:31:25Z joeedh $
# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Jacques Beaurain.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
intern
operators
../avi
../blenfont
../blenkernel
../blenlib
../blenloader
../editors/include
../editors/mesh
../gpu
../ikplugin
../imbuf
../makesdna
../makesrna
../modifiers
../nodes
../render/extern/include
../../../extern/glew/include
../../../intern/audaspace/intern
../../../intern/bsp/extern
../../../intern/decimation/extern
../../../intern/elbeem/extern
../../../intern/guardedalloc
../../../intern/iksolver/extern
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opennl/extern
../../../intern/smoke/extern
# XXX - BAD LEVEL CALL WM_api.h
../../../source/blender/windowmanager
)
set(INC_SYS
${ZLIB_INCLUDE_DIRS}
)
set(SRC
operators/bmo_bevel.c
operators/bmo_connect.c
operators/bmo_create.c
operators/bmo_dissolve.c
operators/bmo_dupe.c
operators/bmo_edgesplit.c
operators/bmo_extrude.c
operators/bmo_join_triangles.c
operators/bmo_mesh_conv.c
operators/bmo_mirror.c
operators/bmo_primitive.c
operators/bmo_removedoubles.c
operators/bmo_subdivide.c
operators/bmo_subdivide.h
operators/bmo_triangulate.c
operators/bmo_utils.c
intern/bmesh_construct.c
intern/bmesh_inline.c
intern/bmesh_interp.c
intern/bmesh_iterators.c
intern/bmesh_iterators_inline.c
intern/bmesh_marking.c
intern/bmesh_mesh.c
intern/bmesh_mods.c
intern/bmesh_newcore.c
intern/bmesh_opdefines.c
intern/bmesh_operators.c
intern/bmesh_operators_private.h
intern/bmesh_polygon.c
intern/bmesh_private.h
intern/bmesh_queries.c
intern/bmesh_structure.c
intern/bmesh_structure.h
intern/bmesh_walkers.c
intern/bmesh_walkers_impl.c
intern/bmesh_walkers_private.h
tools/BME_bevel.c
bmesh.h
bmesh_class.h
bmesh_error.h
bmesh_iterators.h
bmesh_marking.h
bmesh_operator_api.h
bmesh_operators.h
bmesh_queries.h
bmesh_walkers.h
)
add_definitions(-DGLEW_STATIC)
if(WITH_LZO)
add_definitions(-DWITH_LZO)
list(APPEND INC_SYS
../../../extern/lzo/minilzo
)
endif()
if(WITH_LZMA)
add_definitions(-DWITH_LZMA)
list(APPEND INC_SYS
../../../extern/lzma
)
endif()
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
endif()
blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}")

@ -0,0 +1,40 @@
#!/usr/bin/python
Import ('env')
cflags=''
"""
sources = ['intern/bmesh_eulers.c']
sources.append('intern/bmesh_mesh.c')
sources.append('intern/bmesh_polygon.c')
sources.append('intern/bmesh_structure.c')
sources.append('intern/bmesh_marking.c')
sources.append('intern/bmesh_construct.c')
sources.append('intern/bmesh_interp.c')
sources.append('intern/bmesh_filters.c')
sources.append('intern/bmesh_iterators.c')
sources.append('intern/bmesh_mods.c')
sources.append('intern/bmesh_queries.c')
sources.append('intern/bmesh_operators.c')
"""
#sources.append('api/BME_walkers.c')
sources = env.Glob('intern/*.c')
sources += env.Glob('operators/*.c')
#sources += env.Glob('tools/*.c')
incs = ['#/intern/guardedalloc']
incs.append('../blenlib')
incs.append('../blenloader')
incs.append('../makesdna')
incs.append('../makesrna')
incs.append('../blenkernel')
incs.append('./')
incs.append('./intern')
incs.append('../editors/mesh')
incs.append('../editors/include')
defs = []
env.BlenderLib ( libname = 'bf_bmesh', sources = sources, includes = Split(incs), libtype = 'core', defines=defs, priority=100, compileflags=cflags )

@ -0,0 +1,382 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Geoffrey Bantle, Levi Schooley.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_H__
#define __BMESH_H__
/** \file blender/bmesh/bmesh.h
* \ingroup bmesh
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "DNA_listBase.h"
#include "DNA_customdata_types.h"
#include "BLI_utildefines.h"
#include "bmesh_class.h"
/*
* short introduction:
*
* the bmesh structure is a boundary representation, supporting non-manifold
* locally modifiable topology. the API is designed to allow clean, maintainable
* code, that never (or almost never) directly inspects the underlying structure.
*
* The API includes iterators, including many useful topological iterators;
* walkers, which walk over a mesh, without the risk of hitting the recursion
* limit; operators, which are logical, reusable mesh modules; topological
* modification functions (like split face, join faces, etc), which are used for
* topological manipulations; and some (not yet finished) geometric utility
* functions.
*
* some definitions:
*
* tool flags: private flags for tools. each operator has it's own private
* tool flag "layer", which it can use to flag elements.
* tool flags are also used by various other parts of the api.
* header flags: stores persistent flags, such as selection state, hide state,
* etc. be careful of touching these.
*/
/*forward declarations*/
struct BMesh;
struct BMVert;
struct BMEdge;
struct BMFace;
struct BMLoop;
struct BMOperator;
struct Mesh;
struct EditMesh;
/*
* BMHeader
*
* All mesh elements begin with a BMHeader. This structure
* hold several types of data
*
* 1: The type of the element (vert, edge, loop or face)
* 2: Persistant "header" flags/markings (sharp, seam, select, hidden, ect)
note that this is different from the "tool" flags.
* 3: Unique ID in the bmesh.
* 4: some elements for internal record keeping.
*
*/
/* BMHeader->htype (char) */
#define BM_VERT 1
#define BM_EDGE 2
#define BM_LOOP 4
#define BM_FACE 8
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
/* BMHeader->hflag (char) */
#define BM_ELEM_SELECT (1 << 0)
#define BM_ELEM_HIDDEN (1 << 1)
#define BM_ELEM_SEAM (1 << 2)
#define BM_ELEM_SMOOTH (1 << 3) /* used for faces and edges, note from the user POV,
* this is a sharp edge when disabled */
#define BM_ELEM_TAG (1 << 4) /* internal flag, used for ensuring correct normals
* during multires interpolation, and any other time
* when temp tagging is handy.
* always assume dirty & clear before use. */
#define BM_ELEM_FREESTYLE (1 << 5) /* used for faces and edges */
/* we have 3 spare flags which is awesome but since we're limited to 8
* only add new flags with care! - campbell */
/* #define BM_ELEM_SPARE (1<<5) */
/* #define BM_ELEM_SPARE (1<<6) */
/* #define BM_ELEM_NONORMCALC (1<<7) */ /* UNUSED */
/* stub */
void bmesh_error(void);
/* Mesh Level Ops */
extern int bm_mesh_allocsize_default[4];
/* ob is needed by multires */
BMesh *BM_mesh_create(struct Object *ob, const int allocsize[4]);
BMesh *BM_mesh_copy(BMesh *bmold);
void BM_mesh_free(BMesh *bm);
/* frees mesh, but not actual BMesh struct */
void BM_mesh_data_free(BMesh *bm);
void BM_mesh_normals_update(BMesh *bm);
/* Construction */
BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example);
BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, int nodouble);
BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, int nodouble);
BMFace *BM_face_create_quad_tri_v(BMesh *bm,
BMVert **verts, int len,
const BMFace *example, const int nodouble);
/* easier to use version of BM_face_create_quad_tri_v.
* creates edges if necassary. */
BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
const BMFace *example, const int nodouble);
/* makes an ngon from an unordered list of edges. v1 and v2 must be the verts
* defining edges[0], and define the winding of the new face. */
BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble);
/* stuff for dealing with header flags */
BM_INLINE char BM_elem_flag_test(const void *element, const char hflag);
/* stuff for dealing with header flags */
BM_INLINE void BM_elem_flag_enable(void *element, const char hflag);
/* stuff for dealing with header flags */
BM_INLINE void BM_elem_flag_disable(void *element, const char hflag);
/* stuff for dealing BM_elem_flag_toggle header flags */
BM_INLINE void BM_elem_flag_toggle(void *element, const char hflag);
BM_INLINE void BM_elem_flag_merge(void *element_a, void *element_b);
/* notes on BM_elem_index_set(...) usage,
* Set index is sometimes abused as temp storage, other times we cant be
* sure if the index values are valid because certain operations have modified
* the mesh structure.
*
* To set the elements to valid indicies 'BM_mesh_elem_index_ensure' should be used
* rather then adding inline loops, however there are cases where we still
* set the index directly
*
* In an attempt to manage this, here are 3 tags Im adding to uses of
* 'BM_elem_index_set'
*
* - 'set_inline' -- since the data is already being looped over set to a
* valid value inline.
*
* - 'set_dirty!' -- intentionally sets the index to an invalid value,
* flagging 'bm->elem_index_dirty' so we dont use it.
*
* - 'set_ok' -- this is valid use since the part of the code is low level.
*
* - 'set_ok_invalid' -- set to -1 on purpose since this should not be
* used without a full array re-index, do this on
* adding new vert/edge/faces since they may be added at
* the end of the array.
*
* - 'set_loop' -- currently loop index values are not used used much so
* assume each case they are dirty.
* - campbell */
BM_INLINE void BM_elem_index_set(void *element, const int index);
BM_INLINE int BM_elem_index_get(const void *element);
/* todo */
BMFace *BM_face_copy(BMesh *bm, BMFace *f, int copyedges, int copyverts);
/* copies loop data from adjacent faces */
void BM_face_copy_shared(BMesh *bm, BMFace *f);
/* copies attributes, e.g. customdata, header flags, etc, from one element
* to another of the same type.*/
void BM_elem_attrs_copy(BMesh *source_mesh, BMesh *target_mesh, const void *source, void *target);
/* Modification */
/* join two adjacent faces together along an edge. note that
* the faces must only be joined by on edge. e is the edge you
* wish to dissolve.*/
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
/* generic, flexible join faces function; note that most everything uses
* this, including BM_faces_join_pair */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface);
/* split a face along two vertices. returns the newly made face, and sets
* the nl member to a loop in the newly created edge.*/
BMFace *BM_face_split(BMesh *bm, BMFace *f,
BMVert *v1, BMVert *v2,
struct BMLoop **nl, BMEdge *example);
/* these 2 functions are very similar */
BMEdge* BM_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, const int join_faces);
BMEdge* BM_vert_collapse_edges(BMesh *bm, BMEdge *ke, BMVert *kv);
/* splits an edge. ne is set to the new edge created. */
BMVert *BM_edge_split(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent);
/* split an edge multiple times evenly */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts);
/* connect two verts together, through a face they share. this function may
* be removed in the future. */
BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf);
/* rotates an edge topologically, either clockwise (if ccw=0) or counterclockwise
* (if ccw is 1). */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw);
/* Rip a single face from a vertex fan */
BMVert *BM_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv);
/*updates a face normal*/
void BM_face_normal_update(BMesh *bm, BMFace *f);
void BM_face_normal_update_vcos(BMesh *bm, BMFace *f, float no[3], float (*vertexCos)[3]);
/*updates face and vertex normals incident on an edge*/
void BM_edge_normals_update(BMesh *bm, BMEdge *e);
/*update a vert normal (but not the faces incident on it)*/
void BM_vert_normal_update(BMesh *bm, BMVert *v);
void BM_vert_normal_update_all(BMesh *bm, BMVert *v);
void BM_face_normal_flip(BMesh *bm, BMFace *f);
/*dissolves all faces around a vert, and removes it.*/
int BM_disk_dissolve(BMesh *bm, BMVert *v);
/* dissolves vert, in more situations then BM_disk_dissolve
* (e.g. if the vert is part of a wire edge, etc).*/
int BM_vert_dissolve(BMesh *bm, BMVert *v);
/* Projects co onto face f, and returns true if it is inside
* the face bounds. Note that this uses a best-axis projection
* test, instead of projecting co directly into f's orientation
* space, so there might be accuracy issues.*/
int BM_face_point_inside_test(BMesh *bm, BMFace *f, const float co[3]);
/* Interpolation */
/* projects target onto source for customdata interpolation. note: only
* does loop customdata. multires is handled. */
void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source);
/* projects a single loop, target, onto source for customdata interpolation. multires is handled.
* if do_vertex is true, target's vert data will also get interpolated.*/
void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
int do_vertex, int do_multires);
/* smoothes boundaries between multires grids, including some borders in adjacent faces */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
/* project the multires grid in target onto source's set of multires grids */
void BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source);
void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source);
void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac);
void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, struct BMEdge *e1, const float fac);
void BM_data_layer_add(BMesh *em, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
void BM_data_layer_free(BMesh *em, CustomData *data, int type);
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
float BM_elem_float_data_get(struct CustomData *cd, void *element, int type);
void BM_elem_float_data_set(struct CustomData *cd, void *element, int type, const float val);
/* get the area of the face */
float BM_face_area_calc(BMesh *bm, BMFace *f);
/* computes the centroid of a face, using the center of the bounding box */
void BM_face_center_bounds_calc(BMesh *bm, BMFace *f, float center[3]);
/* computes the centroid of a face, using the mean average */
void BM_face_center_mean_calc(BMesh *bm, BMFace *f, float center[3]);
void BM_mesh_select_mode_flush(BMesh *bm);
/* mode independant flushing up/down */
void BM_mesh_deselect_flush(BMesh *bm);
void BM_mesh_select_flush(BMesh *bm);
/* flag conversion funcs */
char BM_face_flag_from_mflag(const char mflag);
char BM_edge_flag_from_mflag(const short mflag);
char BM_vert_flag_from_mflag(const char mflag);
/* reverse */
char BM_face_flag_to_mflag(BMFace *f);
short BM_edge_flag_to_mflag(BMEdge *e);
char BM_vert_flag_to_mflag(BMVert *v);
/* convert MLoop*** in a bmface to mtface and mcol in
* an MFace*/
void BM_loops_to_corners(BMesh *bm, struct Mesh *me, int findex,
BMFace *f, int numTex, int numCol);
void BM_loop_kill(BMesh *bm, BMLoop *l);
void BM_face_kill(BMesh *bm, BMFace *f);
void BM_edge_kill(BMesh *bm, BMEdge *e);
void BM_vert_kill(BMesh *bm, BMVert *v);
/* kills all edges associated with f, along with any other faces containing
* those edges*/
void BM_face_edges_kill(BMesh *bm, BMFace *f);
/* kills all verts associated with f, along with any other faces containing
* those vertices*/
void BM_face_verts_kill(BMesh *bm, BMFace *f);
/*clear all data in bm*/
void BM_mesh_clear(BMesh *bm);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
const char *msg_a, const char *msg_b);
BMVert *BM_vert_at_index(BMesh *bm, const int index);
BMEdge *BM_edge_at_index(BMesh *bm, const int index);
BMFace *BM_face_at_index(BMesh *bm, const int index);
/*start/stop edit*/
void bmesh_begin_edit(BMesh *bm, int flag);
void bmesh_end_edit(BMesh *bm, int flag);
#ifdef USE_BMESH_HOLES
# define BM_FACE_FIRST_LOOP(p) (((BMLoopList *)((p)->loops.first))->first)
#else
# define BM_FACE_FIRST_LOOP(p) ((p)->l_first)
#endif
/* size to use for static arrays when dealing with NGons,
* alloc after this limit is reached.
* this value is rather arbitrary */
#define BM_NGON_STACK_SIZE 32
/* avoid inf loop, this value is arbtrary
* but should not error on valid cases */
#define BM_LOOP_RADIAL_MAX 10000
#define BM_NGON_MAX 100000
/* include the rest of the API */
#include "bmesh_marking.h"
#include "bmesh_operator_api.h"
#include "bmesh_operators.h"
#include "bmesh_error.h"
#include "bmesh_queries.h"
#include "bmesh_iterators.h"
#include "bmesh_walkers.h"
#include "intern/bmesh_inline.c"
#ifdef __cplusplus
}
#endif
#endif /* __BMESH_H__ */

@ -0,0 +1,190 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Geoffrey Bantle, Levi Schooley, Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_CLASS_H__
#define __BMESH_CLASS_H__
/** \file blender/bmesh/bmesh_class.h
* \ingroup bmesh
*/
/* bmesh data structures */
/* dissable holes for now, these are ifdef'd because they use more memory and cant be saved in DNA currently */
// define USE_BMESH_HOLES
struct BMesh;
struct BMVert;
struct BMEdge;
struct BMLoop;
struct BMFace;
struct BMFlagLayer;
struct BMLayerType;
struct BMSubClassLayer;
struct BLI_mempool;
struct Object;
/*note: it is very important for BMHeader to start with two
pointers. this is a requirement of mempool's method of
iteration.
*/
typedef struct BMHeader {
void *data; /* customdata layers */
int index; /* notes:
* - Use BM_elem_index_get/SetIndex macros for index
* - Unitialized to -1 so we can easily tell its not set.
* - Used for edge/vert/face, check BMesh.elem_index_dirty for valid index values,
* this is abused by various tools which set it dirty.
* - For loops this is used for sorting during tesselation. */
char htype; /* element geometric type (verts/edges/loops/faces) */
char hflag; /* this would be a CD layer, see below */
} BMHeader;
/* note: need some way to specify custom locations for custom data layers. so we can
* make them point directly into structs. and some way to make it only happen to the
* active layer, and properly update when switching active layers.*/
typedef struct BMVert {
BMHeader head;
struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
float co[3];
float no[3];
struct BMEdge *e;
} BMVert;
/* disk link structure, only used by edges */
typedef struct BMDiskLink {
struct BMEdge *next, *prev;
} BMDiskLink;
typedef struct BMEdge {
BMHeader head;
struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
struct BMVert *v1, *v2;
struct BMLoop *l;
/* disk cycle pointers */
BMDiskLink v1_disk_link, v2_disk_link;
} BMEdge;
typedef struct BMLoop {
BMHeader head;
/* notice no flags layer */
struct BMVert *v;
struct BMEdge *e;
struct BMFace *f;
struct BMLoop *radial_next, *radial_prev;
/* these were originally commented as private but are used all over the code */
/* can't use ListBase API, due to head */
struct BMLoop *next, *prev;
} BMLoop;
/* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these dont have a flag layer */
typedef struct BMElemF {
BMHeader head;
struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
} BMElemF;
#ifdef USE_BMESH_HOLES
/* eventually, this structure will be used for supporting holes in faces */
typedef struct BMLoopList {
struct BMLoopList *next, *prev;
struct BMLoop *first, *last;
} BMLoopList;
#endif
typedef struct BMFace {
BMHeader head;
struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */
int len; /*includes all boundary loops*/
#ifdef USE_BMESH_HOLES
int totbounds; /*total boundaries, is one plus the number of holes in the face*/
ListBase loops;
#else
BMLoop *l_first;
#endif
float no[3]; /*yes, we do store this here*/
short mat_nr;
} BMFace;
typedef struct BMFlagLayer {
short f, pflag; /* flags */
} BMFlagLayer;
typedef struct BMesh {
int totvert, totedge, totloop, totface;
int totvertsel, totedgesel, totfacesel;
/* flag index arrays as being dirty so we can check if they are clean and
* avoid looping over the entire vert/edge/face array in those cases.
* valid flags are - BM_VERT | BM_EDGE | BM_FACE.
* BM_LOOP isnt handled so far. */
char elem_index_dirty;
/*element pools*/
struct BLI_mempool *vpool, *epool, *lpool, *fpool;
/*operator api stuff*/
struct BLI_mempool *toolflagpool;
int stackdepth;
struct BMOperator *currentop;
CustomData vdata, edata, ldata, pdata;
#ifdef USE_BMESH_HOLES
struct BLI_mempool *looplistpool;
#endif
/* should be copy of scene select mode */
/* stored in BMEditMesh too, this is a bit confusing,
* make sure the're in sync!
* Only use when the edit mesh cant be accessed - campbell */
short selectmode;
/*ID of the shape key this bmesh came from*/
int shapenr;
int walkers, totflags;
ListBase selected, error_stack;
BMFace *act_face;
ListBase errorstack;
struct Object *ob; /* owner object */
int opflag; /* current operator flag */
} BMesh;
#define BM_VERT 1
#define BM_EDGE 2
#define BM_LOOP 4
#define BM_FACE 8
#endif /* __BMESH_CLASS_H__ */

@ -0,0 +1,72 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_ERROR_H__
#define __BMESH_ERROR_H__
/** \file blender/bmesh/bmesh_error.h
* \ingroup bmesh
*/
/*----------- bmop error system ----------*/
/* pushes an error onto the bmesh error stack.
* if msg is null, then the default message for the errorcode is used.*/
void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg);
/* gets the topmost error from the stack.
* returns error code or 0 if no error.*/
int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op);
int BMO_error_occurred(BMesh *bm);
/* same as geterror, only pops the error off the stack as well */
int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op);
void BMO_error_clear(BMesh *bm);
#if 0
//this is meant for handling errors, like self-intersection test failures.
//it's dangerous to handle errors in general though, so disabled for now.
/* catches an error raised by the op pointed to by catchop.
* errorcode is either the errorcode, or BMERR_ALL for any
* error.*/
int BMO_error_catch_op(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
#endif
#define BM_ELEM_INDEX_VALIDATE(_bm, _msg_a, _msg_b) \
BM_mesh_elem_index_validate(_bm, __FILE__ ":" STRINGIFY(__LINE__), __func__, _msg_a, _msg_b)
/*------ error code defines -------*/
/*error messages*/
#define BMERR_SELF_INTERSECTING 1
#define BMERR_DISSOLVEDISK_FAILED 2
#define BMERR_CONNECTVERT_FAILED 3
#define BMERR_WALKER_FAILED 4
#define BMERR_DISSOLVEFACES_FAILED 5
#define BMERR_DISSOLVEVERTS_FAILED 6
#define BMERR_TESSELATION 7
#define BMERR_NONMANIFOLD 8
#define BMERR_INVALID_SELECTION 9
#define BMERR_MESH_ERROR 10
#endif /* __BMESH_ERROR_H__ */

@ -0,0 +1,136 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_ITERATORS_H__
#define __BMESH_ITERATORS_H__
/** \file blender/bmesh/bmesh_iterators.h
* \ingroup bmesh
*/
/*
* BMESH ITERATORS
*
* The functions and structures in this file
* provide a unified method for iterating over
* the elements of a mesh and answering simple
* adjacency queries. Tool authors should use
* the iterators provided in this file instead
* of inspecting the structure directly.
*
*/
#include "BLI_mempool.h"
/* Defines for passing to BM_iter_new.
*
* "OF" can be substituted for "around"
* so BM_VERTS_OF_FACE means "vertices
* around a face."
*/
/* these iterator over all elements of a specific
* type in the mesh.*/
#define BM_VERTS_OF_MESH 1
#define BM_EDGES_OF_MESH 2
#define BM_FACES_OF_MESH 3
/*these are topological iterators.*/
#define BM_EDGES_OF_VERT 4
#define BM_FACES_OF_VERT 5
#define BM_LOOPS_OF_VERT 6
#define BM_FACES_OF_EDGE 7
#define BM_VERTS_OF_FACE 8
#define BM_EDGES_OF_FACE 9
#define BM_LOOPS_OF_FACE 10
/* returns elements from all boundaries, and returns
* the first element at the end to flag that we're entering
* a different face hole boundary*/
#define BM_ALL_LOOPS_OF_FACE 11
/* iterate through loops around this loop, which are fetched
* from the other faces in the radial cycle surrounding the
* input loop's edge.*/
#define BM_LOOPS_OF_LOOP 12
#define BM_LOOPS_OF_EDGE 13
#define BM_ITER(ele, iter, bm, itype, data) \
ele = BM_iter_new(iter, bm, itype, data); \
for ( ; ele; ele=BM_iter_step(iter))
#define BM_ITER_INDEX(ele, iter, bm, itype, data, indexvar) \
ele = BM_iter_new(iter, bm, itype, data); \
for (indexvar=0; ele; indexvar++, ele=BM_iter_step(iter))
/*Iterator Structure*/
typedef struct BMIter {
BLI_mempool_iter pooliter;
struct BMVert *firstvert, *nextvert, *vdata;
struct BMEdge *firstedge, *nextedge, *edata;
struct BMLoop *firstloop, *nextloop, *ldata, *l;
struct BMFace *firstpoly, *nextpoly, *pdata;
struct BMesh *bm;
void (*begin)(struct BMIter *iter);
void *(*step)(struct BMIter *iter);
union {
void *p;
int i;
long l;
float f;
} filter;
int count;
char itype;
} BMIter;
void *BM_iter_at_index(struct BMesh *bm, const char htype, void *data, int index);
int BM_iter_as_array(struct BMesh *bm, const char htype, void *data, void **array, const int len);
/* private for bmesh_iterators_inline.c */
void bmiter__vert_of_mesh_begin(struct BMIter *iter);
void *bmiter__vert_of_mesh_step(struct BMIter *iter);
void bmiter__edge_of_mesh_begin(struct BMIter *iter);
void *bmiter__edge_of_mesh_step(struct BMIter *iter);
void bmiter__face_of_mesh_begin(struct BMIter *iter);
void *bmiter__face_of_mesh_step(struct BMIter *iter);
void bmiter__edge_of_vert_begin(struct BMIter *iter);
void *bmiter__edge_of_vert_step(struct BMIter *iter);
void bmiter__face_of_vert_begin(struct BMIter *iter);
void *bmiter__face_of_vert_step(struct BMIter *iter);
void bmiter__loop_of_vert_begin(struct BMIter *iter);
void *bmiter__loop_of_vert_step(struct BMIter *iter);
void bmiter__loops_of_edge_begin(struct BMIter *iter);
void *bmiter__loops_of_edge_step(struct BMIter *iter);
void bmiter__loops_of_loop_begin(struct BMIter *iter);
void *bmiter__loops_of_loop_step(struct BMIter *iter);
void bmiter__face_of_edge_begin(struct BMIter *iter);
void *bmiter__face_of_edge_step(struct BMIter *iter);
void bmiter__vert_of_face_begin(struct BMIter *iter);
void *bmiter__vert_of_face_step(struct BMIter *iter);
void bmiter__edge_of_face_begin(struct BMIter *iter);
void *bmiter__edge_of_face_step(struct BMIter *iter);
void bmiter__loop_of_face_begin(struct BMIter *iter);
void *bmiter__loop_of_face_step(struct BMIter *iter);
#include "intern/bmesh_iterators_inline.c"
#endif /* __BMESH_ITERATORS_H__ */

@ -0,0 +1,75 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_MARKING_H__
#define __BMESH_MARKING_H__
/** \file blender/bmesh/bmesh_marking.h
* \ingroup bmesh
*/
typedef struct BMEditSelection
{
struct BMEditSelection *next, *prev;
void *data;
char htype;
} BMEditSelection;
/* geometry hiding code */
void BM_elem_hide_set(BMesh *bm, void *element, int hide);
void BM_vert_hide_set(BMesh *bm, BMVert *v, int hide);
void BM_edge_hide_set(BMesh *bm, BMEdge *e, int hide);
void BM_face_hide_set(BMesh *bm, BMFace *f, int hide);
/* Selection code */
void BM_elem_select_set(struct BMesh *bm, void *element, int select);
/* use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection */
void BM_mesh_elem_flag_enable_all(BMesh *bm, const char htype, const char hflag);
void BM_mesh_elem_flag_disable_all(BMesh *bm, const char htype, const char hflag);
/* individual element select functions, BM_elem_select_set is a shortcut for these
* that automatically detects which one to use*/
void BM_vert_select_set(struct BMesh *bm, struct BMVert *v, int select);
void BM_edge_select_set(struct BMesh *bm, struct BMEdge *e, int select);
void BM_face_select_set(struct BMesh *bm, struct BMFace *f, int select);
void BM_select_mode_set(struct BMesh *bm, int selectmode);
/* counts number of elements with flag set */
int BM_mesh_count_flag(struct BMesh *bm, const char htype, const char hflag, int respecthide);
/* edit selection stuff */
void BM_active_face_set(BMesh *em, BMFace *f);
BMFace *BM_active_face_get(BMesh *bm, int sloppy);
void BM_editselection_center(BMesh *bm, float r_center[3], BMEditSelection *ese);
void BM_editselection_normal(float r_normal[3], BMEditSelection *ese);
void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese);
int BM_select_history_check(BMesh *bm, void *data);
void BM_select_history_remove(BMesh *bm, void *data);
void BM_select_history_store(BMesh *bm, void *data);
void BM_select_history_validate(BMesh *bm);
void BM_select_history_clear(BMesh *em);
#endif /* __BMESH_MARKING_H__ */

@ -0,0 +1,555 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_OPERATOR_API_H__
#define __BMESH_OPERATOR_API_H__
/** \file blender/bmesh/bmesh_operator_api.h
* \ingroup bmesh
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "BLI_memarena.h"
#include "BLI_ghash.h"
#include "BKE_utildefines.h"
#include <stdarg.h>
#include <string.h> /* for memcpy */
/*
* operators represent logical, executable mesh modules. all topological
* operations involving a bmesh has to go through them.
*
* operators are nested, as are tool flags, which are private to an operator
* when it's executed. tool flags are allocated in layers, one per operator
* execution, and are used for all internal flagging a tool needs to do.
*
* each operator has a series of "slots," which can be of the following types:
* - simple numerical types
* - arrays of elements (e.g. arrays of faces).
* - hash mappings.
*
* each slot is identified by a slot code, as are each operator.
* operators, and their slots, are defined in bmesh_opdefines.c (with their
* execution functions prototyped in bmesh_operators_private.h), with all their
* operator code and slot codes defined in bmesh_operators.h. see
* bmesh_opdefines.c and the BMOpDefine struct for how to define new operators.
*
* in general, operators are fed arrays of elements, created using either
* BM_HeaderFlag_To_Slot or BM_Flag_To_Slot (or through one of the format
* specifyers in BMO_op_callf or BMO_op_initf). Note that multiple element
* types (e.g. faces and edges) can be fed to the same slot array. Operators
* act on this data, and possibly spit out data into output slots.
*
* some notes:
* - operators should never read from header flags (e.g. element->head.flag). for
* example, if you want an operator to only operate on selected faces, you
* should use BM_HeaderFlag_To_Slot to put the selected elements into a slot.
* - when you read from an element slot array or mapping, you can either tool-flag
* all the elements in it, or read them using an iterator APi (which is
* semantically similar to the iterator api in bmesh_iterators.h).
*/
struct GHashIterator;
/* slot type arrays are terminated by the last member
* having a slot type of 0.*/
#define BMO_OP_SLOT_SENTINEL 0
#define BMO_OP_SLOT_INT 1
#define BMO_OP_SLOT_FLT 2
#define BMO_OP_SLOT_PNT 3
#define BMO_OP_SLOT_MAT 4
#define BMO_OP_SLOT_VEC 7
/* after BMO_OP_SLOT_VEC, everything is
* dynamically allocated arrays. we
* leave a space in the identifiers
* for future growth.
*/
//it's very important this remain a power of two
#define BMO_OP_SLOT_ELEMENT_BUF 8
#define BMO_OP_SLOT_MAPPING 9
/* #define BMO_OP_SLOT_TOTAL_TYPES 10 */ /* not used yet */
/* please ignore all these structures, don't touch them in tool code, except
* for when your defining an operator with BMOpDefine.*/
typedef struct BMOpSlot{
int slottype;
int len;
int flag;
int index; /* index within slot array */
union {
int i;
float f;
void *p;
float vec[3];
void *buf;
GHash *ghash;
} data;
} BMOpSlot;
#define BMO_OP_MAX_SLOTS 16 /* way more than probably needed */
#ifdef slots
#undef slots
#endif
typedef struct BMOperator {
int type;
int slottype;
int needflag;
int flag;
struct BMOpSlot slots[BMO_OP_MAX_SLOTS];
void (*exec)(struct BMesh *bm, struct BMOperator *op);
MemArena *arena;
} BMOperator;
#define MAX_SLOTNAME 32
typedef struct BMOSlotType {
int type;
char name[MAX_SLOTNAME];
} BMOSlotType;
typedef struct BMOpDefine {
const char *name;
BMOSlotType slottypes[BMO_OP_MAX_SLOTS];
void (*exec)(BMesh *bm, BMOperator *op);
int flag;
} BMOpDefine;
/* BMOpDefine->flag */
#define BMO_OP_FLAG_UNTAN_MULTIRES 1 /*switch from multires tangent space to absolute coordinates*/
/* ensures consistent normals before operator execution,
* restoring the original ones windings/normals afterwards.
* keep in mind, this won't work if the input mesh isn't
* manifold.*/
#define BMO_OP_FLAG_RATIONALIZE_NORMALS 2
/*------------- Operator API --------------*/
/* data types that use pointers (arrays, etc) should never
* have it set directly. and never use BMO_slot_ptr_set to
* pass in a list of edges or any arrays, really.*/
void BMO_op_init(struct BMesh *bm, struct BMOperator *op, const char *opname);
/* executes an operator, pushing and popping a new tool flag
* layer as appropriate.*/
void BMO_op_exec(struct BMesh *bm, struct BMOperator *op);
/* finishes an operator (though note the operator's tool flag is removed
* after it finishes executing in BMO_op_exec).*/
void BMO_op_finish(struct BMesh *bm, struct BMOperator *op);
/* tool flag API. never, ever ever should tool code put junk in
* header flags (element->head.flag), nor should they use
* element->head.eflag1/eflag2. instead, use this api to set
* flags.
*
* if you need to store a value per element, use a
* ghash or a mapping slot to do it. */
/* flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use */
#define BMO_elem_flag_test(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f & (oflag))
#define BMO_elem_flag_enable(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f |= (oflag))
#define BMO_elem_flag_disable(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f &= ~(oflag))
#define BMO_elem_flag_toggle(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f ^= (oflag))
/* profiling showed a significant amount of time spent in BMO_elem_flag_test */
#if 0
void BMO_elem_flag_enable(struct BMesh *bm, void *element, const short oflag);
void BMO_elem_flag_disable(struct BMesh *bm, void *element, const short oflag);
int BMO_elem_flag_test(struct BMesh *bm, void *element, const short oflag);
#endif
/* count the number of elements with a specific flag.
* type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
int BMO_mesh_flag_count(struct BMesh *bm, const short oflag, const char htype);
/*---------formatted operator initialization/execution-----------*/
/*
* this system is used to execute or initialize an operator,
* using a formatted-string system.
*
* for example, BMO_op_callf(bm, "del geom=%hf context=%d", BM_ELEM_SELECT, DEL_FACES);
* . . .will execute the delete operator, feeding in selected faces, deleting them.
*
* the basic format for the format string is:
* [operatorname] [slotname]=%[code] [slotname]=%[code]
*
* as in printf, you pass in one additional argument to the function
* for every code.
*
* the formatting codes are:
* %d - put int in slot
* %f - put float in slot
* %p - put pointer in slot
* %h[f/e/v] - put elements with a header flag in slot.
* the letters after %h define which element types to use,
* so e.g. %hf will do faces, %hfe will do faces and edges,
* %hv will do verts, etc. must pass in at least one
* element type letter.
* %f[f/e/v] - same as %h, except it deals with tool flags instead of
* header flags.
* %a[f/e/v] - pass all elements (of types specified by f/e/v) to the
* slot.
* %e - pass in a single element.
* %v - pointer to a float vector of length 3.
* %m[3/4] - matrix, 3/4 refers to the matrix size, 3 or 4. the
* corrusponding argument must be a pointer to
* a float matrix.
* %s - copy a slot from another op, instead of mapping to one
* argument, it maps to two, a pointer to an operator and
* a slot name.
*/
void BMO_push(BMesh *bm, BMOperator *op);
void BMO_pop(BMesh *bm);
/*executes an operator*/
int BMO_op_callf(BMesh *bm, const char *fmt, ...);
/* initializes, but doesn't execute an operator. this is so you can
* gain access to the outputs of the operator. note that you have
* to execute/finitsh (BMO_op_exec and BMO_op_finish) yourself. */
int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...);
/* va_list version, used to implement the above two functions,
* plus EDBM_CallOpf in bmeshutils.c. */
int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *fmt, va_list vlist);
/* test whether a named slot exists */
int BMO_slot_exists(struct BMOperator *op, const char *slotname);
/* get a pointer to a slot. this may be removed layer on from the public API. */
BMOpSlot *BMO_slot_get(struct BMOperator *op, const char *slotname);
/* copies the data of a slot from one operator to another. src and dst are the
* source/destination slot codes, respectively. */
void BMO_slot_copy(struct BMOperator *source_op, struct BMOperator *dest_op,
const char *src, const char *dst);
/* remove tool flagged elements */
void BMO_remove_tagged_faces(struct BMesh *bm, const short oflag);
void BMO_remove_tagged_edges(struct BMesh *bm, const short oflag);
void BMO_remove_tagged_verts(struct BMesh *bm, const short oflag);
/* take care, uses operator flag DEL_WIREVERT */
void BMO_remove_tagged_context(BMesh *bm, const short oflag, const int type);
/* del "context" slot values, used for operator too */
enum {
DEL_VERTS = 1,
DEL_EDGES,
DEL_ONLYFACES,
DEL_EDGESFACES,
DEL_FACES,
DEL_ALL ,
DEL_ONLYTAGGED
};
void BMO_op_flag_enable(struct BMesh *bm, struct BMOperator *op, const int op_flag);
void BMO_op_flag_disable(struct BMesh *bm, struct BMOperator *op, const int op_flag);
void BMO_slot_float_set(struct BMOperator *op, const char *slotname, const float f);
float BMO_slot_float_get(BMOperator *op, const char *slotname);
void BMO_slot_int_set(struct BMOperator *op, const char *slotname, const int i);
int BMO_slot_int_get(BMOperator *op, const char *slotname);
/* don't pass in arrays that are supposed to map to elements this way.
*
* so, e.g. passing in list of floats per element in another slot is bad.
* passing in, e.g. pointer to an editmesh for the conversion operator is fine
* though. */
void BMO_slot_ptr_set(struct BMOperator *op, const char *slotname, void *p);
void *BMO_slot_ptr_get(BMOperator *op, const char *slotname);
void BMO_slot_vec_set(struct BMOperator *op, const char *slotname, const float vec[3]);
void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3]);
/* only supports square mats */
/* size must be 3 or 4; this api is meant only for transformation matrices.
* note that internally the matrix is stored in 4x4 form, and it's safe to
* call whichever BMO_Get_Mat* function you want. */
void BMO_slot_mat_set(struct BMOperator *op, const char *slotname, const float *mat, int size);
void BMO_slot_mat4_get(struct BMOperator *op, const char *slotname, float r_mat[4][4]);
void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float r_mat[3][3]);
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
/* puts every element of type type (which is a bitmask) with tool flag flag,
* into a slot. */
void BMO_slot_from_flag(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const short oflag, const char htype);
/* tool-flags all elements inside an element slot array with flag flag. */
void BMO_slot_buffer_flag_enable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const short oflag, const char htype);
/* clears tool-flag flag from all elements inside a slot array. */
void BMO_slot_buffer_flag_disable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const short oflag, const char htype);
/* tool-flags all elements inside an element slot array with flag flag. */
void BMO_slot_buffer_hflag_enable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const char hflag, const char htype);
/* clears tool-flag flag from all elements inside a slot array. */
void BMO_slot_buffer_hflag_disable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const char hflag, const char htype);
/* puts every element of type type (which is a bitmask) with header flag
* flag, into a slot. note: ignores hidden elements (e.g. elements with
* header flag BM_ELEM_HIDDEN set).*/
void BMO_slot_from_hflag(struct BMesh *bm, struct BMOperator *op, const char *slotname,
const char hflag, const char htype);
/* counts number of elements inside a slot array. */
int BMO_slot_buf_count(struct BMesh *bm, struct BMOperator *op, const char *slotname);
int BMO_slot_map_count(struct BMesh *bm, struct BMOperator *op, const char *slotname);
/* Counts the number of edges with tool flag toolflag around
*/
int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag);
/* inserts a key/value mapping into a mapping slot. note that it copies the
* value, it doesn't store a reference to it. */
#if 0
BM_INLINE void BMO_slot_map_insert(BMesh *bm, BMOperator *op, const char *slotname,
void *element, void *data, int len);
/* inserts a key/float mapping pair into a mapping slot. */
BM_INLINE void BMO_slot_map_float_insert(BMesh *bm, BMOperator *op, const char *slotname,
void *element, float val);
/* returns 1 if the specified pointer is in the map. */
BM_INLINE int BMO_slot_map_contains(BMesh *bm, BMOperator *op, const char *slotname, void *element);
/* returns a point to the value of a specific key. */
BM_INLINE void *BMO_slot_map_data_get(BMesh *bm, BMOperator *op, const char *slotname, void *element);
/* returns the float part of a key/float pair. */
BM_INLINE float BMO_slot_map_float_get(BMesh *bm, BMOperator *op, const char *slotname, void *element);
#endif
/* flags all elements in a mapping. note that the mapping must only have
* bmesh elements in it.*/
void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
const char *slotname, const short oflag);
/* pointer versoins of BMO_slot_map_float_get and BMO_slot_map_float_insert.
*
* do NOT use these for non-operator-api-allocated memory! instead
* use BMO_slot_map_data_get and BMO_slot_map_insert, which copies the data. */
#if 0
BM_INLINE void BMO_slot_map_ptr_insert(BMesh *bm, BMOperator *op, const char *slotname, void *key, void *val);
BM_INLINE void *BMO_slot_map_ptr_get(BMesh *bm, BMOperator *op, const char *slotname, void *key);
#endif
/* this part of the API is used to iterate over element buffer or
* mapping slots.
*
* for example, iterating over the faces in a slot is:
*
* BMOIter oiter;
* BMFace *f;
*
* f = BMO_iter_new(&oiter, bm, some_operator, "slotname", BM_FACE);
* for (; f; f=BMO_iter_step(&oiter)) {
* /do something with the face
* }
*
* another example, iterating over a mapping:
* BMOIter oiter;
* void *key;
* void *val;
*
* key = BMO_iter_new(&oiter, bm, some_operator, "slotname", 0);
* for (; key; key=BMO_iter_step(&oiter)) {
* val = BMO_iter_map_value(&oiter);
* //do something with the key/val pair
* //note that val is a pointer to the val data,
* //whether it's a float, pointer, whatever.
* //
* // so to get a pointer, for example, use:
* // *((void**)BMO_iter_map_value(&oiter));
* //or something like that.
* }
*/
/* contents of this structure are private,
* don't directly access. */
typedef struct BMOIter {
BMOpSlot *slot;
int cur; //for arrays
struct GHashIterator giter;
void *val;
char restrictmask; /* bitwise '&' with BMHeader.htype */
} BMOIter;
void *BMO_slot_elem_first(BMOperator *op, const char *slotname);
/* restrictmask restricts the iteration to certain element types
* (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
* over an element buffer (not a mapping).*/
void *BMO_iter_new(BMOIter *iter, BMesh *bm, BMOperator *op,
const char *slotname, const char restrictmask);
void *BMO_iter_step(BMOIter *iter);
/* returns a pointer to the key value when iterating over mappings.
* remember for pointer maps this will be a pointer to a pointer.*/
void *BMO_iter_map_value(BMOIter *iter);
/* use this for pointer mappings */
void *BMO_iter_map_value_p(BMOIter *iter);
/* use this for float mappings */
float BMO_iter_map_value_f(BMOIter *iter);
#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \
ele = BMO_iter_new(iter, bm, op, slotname, restrict); \
for ( ; ele; ele=BMO_iter_step(iter))
/******************* Inlined Functions********************/
typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op);
/* mappings map elements to data, which
* follows the mapping struct in memory. */
typedef struct BMOElemMapping {
BMHeader *element;
int len;
} BMOElemMapping;
extern const int BMO_OPSLOT_TYPEINFO[];
BM_INLINE void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
void *element, void *data, int len)
{
BMOElemMapping *mapping;
BMOpSlot *slot = BMO_slot_get(op, slotname);
/*sanity check*/
if (slot->slottype != BMO_OP_SLOT_MAPPING) {
return;
}
mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
mapping->element = (BMHeader*) element;
mapping->len = len;
memcpy(mapping + 1, data, len);
if (!slot->data.ghash) {
slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
BLI_ghashutil_ptrcmp, "bmesh op");
}
BLI_ghash_insert(slot->data.ghash, element, mapping);
}
BM_INLINE void BMO_slot_map_int_insert(BMesh *bm, BMOperator *op, const char *slotname,
void *element, int val)
{
BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(int));
}
BM_INLINE void BMO_slot_map_float_insert(BMesh *bm, BMOperator *op, const char *slotname,
void *element, float val)
{
BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(float));
}
BM_INLINE void BMO_slot_map_ptr_insert(BMesh *bm, BMOperator *op, const char *slotname,
void *element, void *val)
{
BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(void*));
}
BM_INLINE int BMO_slot_map_contains(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, void *element)
{
BMOpSlot *slot = BMO_slot_get(op, slotname);
/*sanity check*/
if (slot->slottype != BMO_OP_SLOT_MAPPING) return 0;
if (!slot->data.ghash) return 0;
return BLI_ghash_haskey(slot->data.ghash, element);
}
BM_INLINE void *BMO_slot_map_data_get(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
void *element)
{
BMOElemMapping *mapping;
BMOpSlot *slot = BMO_slot_get(op, slotname);
/*sanity check*/
if (slot->slottype != BMO_OP_SLOT_MAPPING) return NULL;
if (!slot->data.ghash) return NULL;
mapping = (BMOElemMapping *)BLI_ghash_lookup(slot->data.ghash, element);
if (!mapping) return NULL;
return mapping + 1;
}
BM_INLINE float BMO_slot_map_float_get(BMesh *bm, BMOperator *op, const char *slotname,
void *element)
{
float *val = (float*) BMO_slot_map_data_get(bm, op, slotname, element);
if (val) return *val;
return 0.0f;
}
BM_INLINE int BMO_slot_map_int_get(BMesh *bm, BMOperator *op, const char *slotname,
void *element)
{
int *val = (int*) BMO_slot_map_data_get(bm, op, slotname, element);
if (val) return *val;
return 0;
}
BM_INLINE void *BMO_slot_map_ptr_get(BMesh *bm, BMOperator *op, const char *slotname,
void *element)
{
void **val = (void**) BMO_slot_map_data_get(bm, op, slotname, element);
if (val) return *val;
return NULL;
}
#ifdef __cplusplus
}
#endif
#endif /* __BMESH_OPERATOR_API_H__ */

@ -0,0 +1,107 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_OPERATORS_H__
#define __BMESH_OPERATORS_H__
/** \file blender/bmesh/bmesh_operators.h
* \ingroup bmesh
*/
/*see comments in intern/bmesh_opdefines.c for documentation of specific operators*/
/*--------defines/enumerations for specific operators-------*/
/*quad innervert values*/
enum {
SUBD_INNERVERT,
SUBD_PATH,
SUBD_FAN,
SUBD_STRAIGHT_CUT
};
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,
SIMFACE_IMAGE,
SIMFACE_AREA,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
SIMFACE_COPLANAR,
SIMFACE_FREESTYLE
};
/* similar edge selection slot values */
enum {
SIMEDGE_LENGTH = 101,
SIMEDGE_DIR,
SIMEDGE_FACE,
SIMEDGE_FACE_ANGLE,
SIMEDGE_CREASE,
SIMEDGE_SEAM,
SIMEDGE_SHARP,
SIMEDGE_FREESTYLE
};
/* similar vertex selection slot values */
enum {
SIMVERT_NORMAL = 0,
SIMVERT_FACE,
SIMVERT_VGROUP
};
enum {
OPUVC_AXIS_X = 1,
OPUVC_AXIS_Y
};
enum {
DIRECTION_CW = 1,
DIRECTION_CCW
};
/* vertex path selection values */
enum {
VPATH_SELECT_EDGE_LENGTH = 0,
VPATH_SELECT_TOPOLOGICAL
};
extern BMOpDefine *opdefines[];
extern int bmesh_total_ops;
/*------specific operator helper functions-------*/
/* executes the duplicate operation, feeding elements of
* type flag etypeflag and header flag flag to it. note,
* to get more useful information (such as the mapping from
* original to new elements) you should run the dupe op manually.*/
struct Object;
struct EditMesh;
#if 0
void BMO_dupe_from_flag(struct BMesh *bm, int etypeflag, const char hflag);
#endif
void BM_mesh_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth,
float fractal, int beauty, int numcuts, int seltype,
int cornertype, int singleedge, int gridfill, int seed);
#endif /* __BMESH_OPERATORS_H__ */

@ -0,0 +1,123 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_QUERIES_H__
#define __BMESH_QUERIES_H__
/** \file blender/bmesh/bmesh_queries.h
* \ingroup bmesh
*/
#include <stdio.h>
/* Queries */
/* counts number of elements of type type are in the mesh. */
int BM_mesh_elem_count(struct BMesh *bm, const char htype);
/*returns true if v is in f*/
int BM_vert_in_face(struct BMFace *f, struct BMVert *v);
// int BM_verts_in_face(struct BMFace *f, struct BMVert **varr, int len);
int BM_verts_in_face(struct BMesh *bm, struct BMFace *f, struct BMVert **varr, int len);
int BM_edge_in_face(struct BMFace *f, struct BMEdge *e);
int BM_vert_in_edge(struct BMEdge *e, struct BMVert *v);
int BM_verts_in_edge(struct BMVert *v1, struct BMVert *v2, struct BMEdge *e);
/*get opposing vert from v in edge e.*/
struct BMVert *BM_edge_other_vert(struct BMEdge *e, struct BMVert *v);
/*finds other loop that shares v with e's loop in f.*/
struct BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v);
/*returns the edge existing between v1 and v2, or NULL if there isn't one.*/
struct BMEdge *BM_edge_exists(struct BMVert *v1, struct BMVert *v2);
/*returns number of edges aroudn a vert*/
int BM_vert_edge_count(struct BMVert *v);
/*returns number of faces around an edge*/
int BM_edge_face_count(struct BMEdge *e);
/*returns number of faces around a vert.*/
int BM_vert_face_count(struct BMVert *v);
/*returns true if v is a wire vert*/
int BM_vert_is_wire(struct BMesh *bm, struct BMVert *v);
/*returns true if e is a wire edge*/
int BM_edge_is_wire(struct BMesh *bm, struct BMEdge *e);
/* returns FALSE if v is part of a non-manifold edge in the mesh,
* I believe this includes if it's part of both a wire edge and
* a face.*/
int BM_vert_is_manifold(struct BMesh *bm, struct BMVert *v);
/* returns FALSE if e is shared by more then two faces. */
int BM_edge_is_manifold(struct BMesh *bm, struct BMEdge *e);
/* returns true if e is a boundary edge, e.g. has only 1 face bordering it. */
int BM_edge_is_boundry(struct BMEdge *e);
/* returns angle of two faces surrounding an edge. note there must be
* exactly two faces sharing the edge.*/
float BM_edge_face_angle(struct BMesh *bm, struct BMEdge *e);
/* returns angle of two faces surrounding edges. note there must be
* exactly two edges sharing the vertex.*/
float BM_vert_edge_angle(struct BMesh *bm, struct BMVert *v);
/* checks overlapping of existing faces with the verts in varr. */
int BM_face_exists_overlap(struct BMesh *bm, struct BMVert **varr, int len, struct BMFace **existface);
/* checks if a face defined by varr already exists. */
int BM_face_exists(BMesh *bm, BMVert **varr, int len, BMFace **existface);
/* returns number of edges f1 and f2 share. */
int BM_face_share_edges(struct BMFace *f1, struct BMFace *f2);
/* returns number of faces e1 and e2 share. */
int BM_edge_share_faces(struct BMEdge *e1, struct BMEdge *e2);
/* returns bool 1/0 if the edges share a vertex */
int BM_edge_share_vert(struct BMEdge *e1, struct BMEdge *e2);
/* edge verts in winding order from face */
void BM_edge_ordered_verts(struct BMEdge *edge, struct BMVert **r_v1, struct BMVert **r_v2);
/* checks if a face is valid in the data structure */
int BM_face_validate(BMesh *bm, BMFace *face, FILE *err);
/* each pair of loops defines a new edge, a split. this function goes
* through and sets pairs that are geometrically invalid to null. a
* split is invalid, if it forms a concave angle or it intersects other
* edges in the face.*/
void BM_face_legal_splits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len);
#endif /* __BMESH_QUERIES_H__ */

@ -0,0 +1,139 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BMESH_WALKERS_H__
#define __BMESH_WALKERS_H__
/** \file blender/bmesh/bmesh_walkers.h
* \ingroup bmesh
*/
#include "BLI_ghash.h"
/*
NOTE: do NOT modify topology while walking a mesh!
*/
typedef enum {
BMW_DEPTH_FIRST,
BMW_BREADTH_FIRST
} BMWOrder;
/*Walkers*/
typedef struct BMWalker {
void (*begin) (struct BMWalker *walker, void *start);
void *(*step) (struct BMWalker *walker);
void *(*yield)(struct BMWalker *walker);
int structsize;
BMWOrder order;
int valid_mask;
/* runtime */
int layer;
BMesh *bm;
BLI_mempool *worklist;
ListBase states;
short mask_vert;
short mask_edge;
short mask_loop;
short mask_face;
GHash *visithash;
int depth;
} BMWalker;
/* define to make BMW_init more clear */
#define BMW_MASK_NOP 0
/* initialize a walker. searchmask restricts some (not all) walkers to
* elements with a specific tool flag set. flags is specific to each walker.*/
void BMW_init(struct BMWalker *walker, BMesh *bm, int type,
short mask_vert, short mask_edge, short mask_loop, short mask_face,
int layer);
void *BMW_begin(BMWalker *walker, void *start);
void *BMW_step(struct BMWalker *walker);
void BMW_end(struct BMWalker *walker);
int BMW_current_depth(BMWalker *walker);
/*these are used by custom walkers*/
void *BMW_current_state(BMWalker *walker);
void *BMW_state_add(BMWalker *walker);
void BMW_state_remove(BMWalker *walker);
void *BMW_walk(BMWalker *walker);
void BMW_reset(BMWalker *walker);
/*
example of usage, walking over an island of tool flagged faces:
BMWalker walker;
BMFace *f;
BMW_init(&walker, bm, BMW_ISLAND, SOME_OP_FLAG);
f = BMW_begin(&walker, some_start_face);
for (; f; f=BMW_step(&walker)) {
//do something with f
}
BMW_end(&walker);
*/
enum {
/* walk over connected geometry. can restrict to a search flag,
* or not, it's optional.
*
* takes a vert as an arugment, and spits out edges, restrict flag acts
* on the edges as well. */
BMW_SHELL,
/*walk over an edge loop. search flag doesn't do anything.*/
BMW_LOOP,
BMW_FACELOOP,
BMW_EDGERING,
/* #define BMW_RING 2 */
/* walk over uv islands; takes a loop as input. restrict flag
* restricts the walking to loops whose vert has restrict flag set as a
* tool flag.
*
* the flag parameter to BMW_init maps to a loop customdata layer index.
*/
BMW_LOOPDATA_ISLAND,
/* walk over an island of flagged faces. note, that this doesn't work on
* non-manifold geometry. it might be better to rewrite this to extract
* boundary info from the island walker, rather then directly walking
* over the boundary. raises an error if it encouters nonmanifold
* geometry. */
BMW_ISLANDBOUND,
/* walk over all faces in an island of tool flagged faces. */
BMW_ISLAND,
/* walk from a vertex to all connected vertices. */
BMW_CONNECTED_VERTEX,
/* end of array index enum vals */
/* do not intitialze function pointers and struct size in BMW_init */
BMW_CUSTOM,
BMW_MAXWALKERS
};
/* use with BMW_init, so as not to confuse with restrict flags */
#define BMW_NIL_LAY 0
#endif /* __BMESH_WALKERS_H__ */

@ -0,0 +1,777 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_construct.c
* \ingroup bmesh
*
* BM construction functions.
*/
#include "MEM_guardedalloc.h"
#include "BLI_array.h"
#include "BLI_math.h"
#include "BKE_customdata.h"
#include "DNA_meshdata_types.h"
#include "bmesh.h"
#include "bmesh_private.h"
#define SELECT 1
/* prototypes */
static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
const BMLoop *source_loop, BMLoop *target_loop);
/*
* BMESH MAKE QUADTRIANGLE
*
* Creates a new quad or triangle from
* a list of 3 or 4 vertices. If nodouble
* equals 1, then a check is done to see
* if a face with these vertices already
* exists and returns it instead. If a pointer
* to an example face is provided, it's custom
* data and properties will be copied to the new
* face.
*
* Note that the winding of the face is determined
* by the order of the vertices in the vertex array
*/
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
const BMFace *example, const int nodouble)
{
BMVert *vtar[4] = {v1, v2, v3, v4};
return BM_face_create_quad_tri_v(bm, vtar, v4 ? 4 : 3, example, nodouble);
}
/* remove the edge array bits from this. Its not really needed? */
BMFace *BM_face_create_quad_tri_v(BMesh *bm, BMVert **verts, int len, const BMFace *example, const int nodouble)
{
BMEdge *edar[4] = {NULL};
BMFace *f = NULL;
int overlap = 0;
edar[0] = BM_edge_exists(verts[0], verts[1]);
edar[1] = BM_edge_exists(verts[1], verts[2]);
if (len == 4) {
edar[2] = BM_edge_exists(verts[2], verts[3]);
edar[3] = BM_edge_exists(verts[3], verts[0]);
}
else {
edar[2] = BM_edge_exists(verts[2], verts[0]);
}
if (nodouble) {
/* check if face exists or overlaps */
if (len == 4) {
overlap = BM_face_exists_overlap(bm, verts, len, &f);
}
else {
overlap = BM_face_exists_overlap(bm, verts, len, &f);
}
}
/* make new face */
if ((!f) && (!overlap)) {
if (!edar[0]) edar[0] = BM_edge_create(bm, verts[0], verts[1], NULL, FALSE);
if (!edar[1]) edar[1] = BM_edge_create(bm, verts[1], verts[2], NULL, FALSE);
if (len == 4) {
if (!edar[2]) edar[2] = BM_edge_create(bm, verts[2], verts[3], NULL, FALSE);
if (!edar[3]) edar[3] = BM_edge_create(bm, verts[3], verts[0], NULL, FALSE);
}
else {
if (!edar[2]) edar[2] = BM_edge_create(bm, verts[2], verts[0], NULL, FALSE);
}
f = BM_face_create(bm, verts, edar, len, FALSE);
if (example && f) {
BM_elem_attrs_copy(bm, bm, example, f);
}
}
return f;
}
/* copies face data from shared adjacent faces */
void BM_face_copy_shared(BMesh *bm, BMFace *f)
{
BMIter iter;
BMLoop *l, *l2;
if (!f) return;
l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
for ( ; l; l = BM_iter_step(&iter)) {
l2 = l->radial_next;
if (l2 && l2 != l) {
if (l2->v == l->v) {
bm_loop_attrs_copy(bm, bm, l2, l);
}
else {
l2 = l2->next;
bm_loop_attrs_copy(bm, bm, l2, l);
}
}
}
}
/*
* BMESH MAKE NGON
*
* Attempts to make a new Ngon from a list of edges.
* If nodouble equals one, a check for overlaps or existing
*
* The edges are not required to be ordered, simply to to form
* a single closed loop as a whole
*
* Note that while this function will work fine when the edges
* are already sorted, if the edges are always going to be sorted,
* BM_face_create should be considered over this function as it
* avoids some unnecessary work.
*/
BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
{
BMEdge **edges2 = NULL;
BLI_array_staticdeclare(edges2, BM_NGON_STACK_SIZE);
BMVert **verts = NULL, *v;
BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
BMFace *f = NULL;
BMEdge *e;
BMVert *ev1, *ev2;
int i, /* j, */ v1found, reverse;
/* this code is hideous, yeek. I'll have to think about ways of
* cleaning it up. basically, it now combines the old BM_face_create_ngon
* _and_ the old bmesh_mf functions, so its kindof smashed together
* - joeedh */
if (!len || !v1 || !v2 || !edges || !bm)
return NULL;
/* put edges in correct order */
for (i = 0; i < len; i++) {
BM_ELEM_API_FLAG_ENABLE(edges[i], _FLAG_MF);
}
ev1 = edges[0]->v1;
ev2 = edges[0]->v2;
if (v1 == ev2) {
/* Swapping here improves performance and consistency of face
* structure in the special case that the edges are already in
* the correct order and winding */
SWAP(BMVert *, ev1, ev2);
}
BLI_array_append(verts, ev1);
v = ev2;
e = edges[0];
do {
BMEdge *e2 = e;
BLI_array_append(verts, v);
BLI_array_append(edges2, e);
do {
e2 = bmesh_disk_nextedge(e2, v);
if (e2 != e && BM_ELEM_API_FLAG_TEST(e2, _FLAG_MF)) {
v = BM_edge_other_vert(e2, v);
break;
}
} while (e2 != e);
if (e2 == e)
goto err; /* the edges do not form a closed loop */
e = e2;
} while (e != edges[0]);
if (BLI_array_count(edges2) != len) {
goto err; /* we didn't use all edges in forming the boundary loop */
}
/* ok, edges are in correct order, now ensure they are going
* in the correct direction */
v1found = reverse = FALSE;
for (i = 0; i < len; i++) {
if (BM_vert_in_edge(edges2[i], v1)) {
/* see if v1 and v2 are in the same edge */
if (BM_vert_in_edge(edges2[i], v2)) {
/* if v1 is shared by the *next* edge, then the winding
* is incorrect */
if (BM_vert_in_edge(edges2[(i + 1) % len], v1)) {
reverse = TRUE;
break;
}
}
v1found = TRUE;
}
if ((v1found == FALSE) && BM_vert_in_edge(edges2[i], v2)) {
reverse = TRUE;
break;
}
}
if (reverse) {
for (i = 0; i < len / 2; i++) {
v = verts[i];
verts[i] = verts[len - i - 1];
verts[len - i - 1] = v;
}
}
for (i = 0; i < len; i++) {
edges2[i] = BM_edge_exists(verts[i], verts[(i + 1) % len]);
if (!edges2[i]) {
goto err;
}
}
f = BM_face_create(bm, verts, edges2, len, nodouble);
/* clean up flags */
for (i = 0; i < len; i++) {
BM_ELEM_API_FLAG_DISABLE(edges2[i], _FLAG_MF);
}
BLI_array_free(verts);
BLI_array_free(edges2);
return f;
err:
for (i = 0; i < len; i++) {
BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
}
BLI_array_free(verts);
BLI_array_free(edges2);
return NULL;
}
/* bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */
/*
* REMOVE TAGGED XXX
*
* Called by operators to remove elements that they have marked for
* removal.
*
*/
void BMO_remove_tagged_faces(BMesh *bm, const short oflag)
{
BMFace *f;
BMIter iter;
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (BMO_elem_flag_test(bm, f, oflag)) {
BM_face_kill(bm, f);
}
}
}
void BMO_remove_tagged_edges(BMesh *bm, const short oflag)
{
BMEdge *e;
BMIter iter;
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
if (BMO_elem_flag_test(bm, e, oflag)) {
BM_edge_kill(bm, e);
}
}
}
void BMO_remove_tagged_verts(BMesh *bm, const short oflag)
{
BMVert *v;
BMIter iter;
BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
if (BMO_elem_flag_test(bm, v, oflag)) {
BM_vert_kill(bm, v);
}
}
}
/*************************************************************/
/* you need to make remove tagged verts/edges/faces
* api functions that take a filter callback.....
* and this new filter type will be for opstack flags.
* This is because the BM_remove_taggedXXX functions bypass iterator API.
* - Ops dont care about 'UI' considerations like selection state, hide state, ect.
* If you want to work on unhidden selections for instance,
* copy output from a 'select context' operator to another operator....
*/
static void bmo_remove_tagged_context_verts(BMesh *bm, const short oflag)
{
BMVert *v;
BMEdge *e;
BMFace *f;
BMIter verts;
BMIter edges;
BMIter faces;
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
if (BMO_elem_flag_test(bm, v, oflag)) {
/* Visit edge */
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BM_iter_step(&edges))
BMO_elem_flag_enable(bm, e, oflag);
/* Visit face */
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_VERT, v); f; f = BM_iter_step(&faces))
BMO_elem_flag_enable(bm, f, oflag);
}
}
BMO_remove_tagged_faces(bm, oflag);
BMO_remove_tagged_edges(bm, oflag);
BMO_remove_tagged_verts(bm, oflag);
}
static void bmo_remove_tagged_context_edges(BMesh *bm, const short oflag)
{
BMEdge *e;
BMFace *f;
BMIter edges;
BMIter faces;
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (BMO_elem_flag_test(bm, e, oflag)) {
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BM_iter_step(&faces)) {
BMO_elem_flag_enable(bm, f, oflag);
}
}
}
BMO_remove_tagged_faces(bm, oflag);
BMO_remove_tagged_edges(bm, oflag);
}
#define DEL_WIREVERT (1 << 10)
/* warning, oflag applies to different types in some contexts,
* not just the type being removed */
void BMO_remove_tagged_context(BMesh *bm, const short oflag, const int type)
{
BMVert *v;
BMEdge *e;
BMFace *f;
BMIter verts;
BMIter edges;
BMIter faces;
switch (type) {
case DEL_VERTS:
{
bmo_remove_tagged_context_verts(bm, oflag);
break;
}
case DEL_EDGES:
{
/* flush down to vert */
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (BMO_elem_flag_test(bm, e, oflag)) {
BMO_elem_flag_enable(bm, e->v1, oflag);
BMO_elem_flag_enable(bm, e->v2, oflag);
}
}
bmo_remove_tagged_context_edges(bm, oflag);
/* remove loose vertice */
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
if (BMO_elem_flag_test(bm, v, oflag) && (!(v->e)))
BMO_elem_flag_enable(bm, v, DEL_WIREVERT);
}
BMO_remove_tagged_verts(bm, DEL_WIREVERT);
break;
}
case DEL_EDGESFACES:
{
bmo_remove_tagged_context_edges(bm, oflag);
break;
}
case DEL_ONLYFACES:
{
BMO_remove_tagged_faces(bm, oflag);
break;
}
case DEL_ONLYTAGGED:
{
BMO_remove_tagged_faces(bm, oflag);
BMO_remove_tagged_edges(bm, oflag);
BMO_remove_tagged_verts(bm, oflag);
break;
}
case DEL_FACES:
{
/* go through and mark all edges and all verts of all faces for delet */
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
if (BMO_elem_flag_test(bm, f, oflag)) {
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BM_iter_step(&edges))
BMO_elem_flag_enable(bm, e, oflag);
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&verts))
BMO_elem_flag_enable(bm, v, oflag);
}
}
/* now go through and mark all remaining faces all edges for keeping */
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
if (!BMO_elem_flag_test(bm, f, oflag)) {
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BM_iter_step(&edges)) {
BMO_elem_flag_disable(bm, e, oflag);
}
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&verts)) {
BMO_elem_flag_disable(bm, v, oflag);
}
}
}
/* also mark all the vertices of remaining edges for keeping */
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (!BMO_elem_flag_test(bm, e, oflag)) {
BMO_elem_flag_disable(bm, e->v1, oflag);
BMO_elem_flag_disable(bm, e->v2, oflag);
}
}
/* now delete marked face */
BMO_remove_tagged_faces(bm, oflag);
/* delete marked edge */
BMO_remove_tagged_edges(bm, oflag);
/* remove loose vertice */
BMO_remove_tagged_verts(bm, oflag);
break;
}
case DEL_ALL:
{
/* does this option even belong in here? */
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces))
BMO_elem_flag_enable(bm, f, oflag);
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
BMO_elem_flag_enable(bm, e, oflag);
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts))
BMO_elem_flag_enable(bm, v, oflag);
BMO_remove_tagged_faces(bm, oflag);
BMO_remove_tagged_edges(bm, oflag);
BMO_remove_tagged_verts(bm, oflag);
break;
}
}
}
/*************************************************************/
static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
const BMVert *source_vertex, BMVert *target_vertex)
{
if ((source_mesh == target_mesh) && (source_vertex == target_vertex)) {
return;
}
copy_v3_v3(target_vertex->no, source_vertex->no);
CustomData_bmesh_free_block(&target_mesh->vdata, &target_vertex->head.data);
CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata,
source_vertex->head.data, &target_vertex->head.data);
}
static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
const BMEdge *source_edge, BMEdge *target_edge)
{
if ((source_mesh == target_mesh) && (source_edge == target_edge)) {
return;
}
CustomData_bmesh_free_block(&target_mesh->edata, &target_edge->head.data);
CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata,
source_edge->head.data, &target_edge->head.data);
}
static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
const BMLoop *source_loop, BMLoop *target_loop)
{
if ((source_mesh == target_mesh) && (source_loop == target_loop)) {
return;
}
CustomData_bmesh_free_block(&target_mesh->ldata, &target_loop->head.data);
CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata,
source_loop->head.data, &target_loop->head.data);
}
static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
const BMFace *source_face, BMFace *target_face)
{
if ((source_mesh == target_mesh) && (source_face == target_face)) {
return;
}
copy_v3_v3(target_face->no, source_face->no);
CustomData_bmesh_free_block(&target_mesh->pdata, &target_face->head.data);
CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata,
source_face->head.data, &target_face->head.data);
target_face->mat_nr = source_face->mat_nr;
}
/* BMESH_TODO: Special handling for hide flags? */
void BM_elem_attrs_copy(BMesh *source_mesh, BMesh *target_mesh, const void *source, void *target)
{
const BMHeader *sheader = source;
BMHeader *theader = target;
if (sheader->htype != theader->htype)
return;
/* First we copy select */
if (BM_elem_flag_test(source, BM_ELEM_SELECT)) BM_elem_select_set(target_mesh, target, TRUE);
/* Now we copy flags */
theader->hflag = sheader->hflag;
/* Copy specific attributes */
if (theader->htype == BM_VERT)
bm_vert_attrs_copy(source_mesh, target_mesh, (const BMVert *)source, (BMVert *)target);
else if (theader->htype == BM_EDGE)
bm_edge_attrs_copy(source_mesh, target_mesh, (const BMEdge *)source, (BMEdge *)target);
else if (theader->htype == BM_LOOP)
bm_loop_attrs_copy(source_mesh, target_mesh, (const BMLoop *)source, (BMLoop *)target);
else if (theader->htype == BM_FACE)
bm_face_attrs_copy(source_mesh, target_mesh, (const BMFace *)source, (BMFace *)target);
}
BMesh *BM_mesh_copy(BMesh *bmold)
{
BMesh *bm;
BMVert *v, *v2, **vtable = NULL;
BMEdge *e, *e2, **edges = NULL, **etable = NULL;
BLI_array_declare(edges);
BMLoop *l, /* *l2, */ **loops = NULL;
BLI_array_declare(loops);
BMFace *f, *f2, **ftable = NULL;
BMEditSelection *ese;
BMIter iter, liter;
int i, j;
/* allocate a bmesh */
bm = BM_mesh_create(bmold->ob, bm_mesh_allocsize_default);
CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_bmesh_init_pool(&bm->vdata, bm_mesh_allocsize_default[0]);
CustomData_bmesh_init_pool(&bm->edata, bm_mesh_allocsize_default[1]);
CustomData_bmesh_init_pool(&bm->ldata, bm_mesh_allocsize_default[2]);
CustomData_bmesh_init_pool(&bm->pdata, bm_mesh_allocsize_default[3]);
vtable = MEM_mallocN(sizeof(BMVert *) * bmold->totvert, "BM_mesh_copy vtable");
etable = MEM_mallocN(sizeof(BMEdge *) * bmold->totedge, "BM_mesh_copy etable");
ftable = MEM_mallocN(sizeof(BMFace *) * bmold->totface, "BM_mesh_copy ftable");
v = BM_iter_new(&iter, bmold, BM_VERTS_OF_MESH, NULL);
for (i = 0; v; v = BM_iter_step(&iter), i++) {
v2 = BM_vert_create(bm, v->co, NULL); /* copy between meshes so cant use 'example' argument */
BM_elem_attrs_copy(bmold, bm, v, v2);
vtable[i] = v2;
BM_elem_index_set(v, i); /* set_inline */
BM_elem_index_set(v2, i); /* set_inline */
}
bmold->elem_index_dirty &= ~BM_VERT;
bm->elem_index_dirty &= ~BM_VERT;
/* safety check */
BLI_assert(i == bmold->totvert);
e = BM_iter_new(&iter, bmold, BM_EDGES_OF_MESH, NULL);
for (i = 0; e; e = BM_iter_step(&iter), i++) {
e2 = BM_edge_create(bm,
vtable[BM_elem_index_get(e->v1)],
vtable[BM_elem_index_get(e->v2)],
e, FALSE);
BM_elem_attrs_copy(bmold, bm, e, e2);
etable[i] = e2;
BM_elem_index_set(e, i); /* set_inline */
BM_elem_index_set(e2, i); /* set_inline */
}
bmold->elem_index_dirty &= ~BM_EDGE;
bm->elem_index_dirty &= ~BM_EDGE;
/* safety check */
BLI_assert(i == bmold->totedge);
f = BM_iter_new(&iter, bmold, BM_FACES_OF_MESH, NULL);
for (i = 0; f; f = BM_iter_step(&iter), i++) {
BM_elem_index_set(f, i); /* set_inline */
BLI_array_empty(loops);
BLI_array_empty(edges);
BLI_array_growitems(loops, f->len);
BLI_array_growitems(edges, f->len);
l = BM_iter_new(&liter, bmold, BM_LOOPS_OF_FACE, f);
for (j = 0; j < f->len; j++, l = BM_iter_step(&liter)) {
loops[j] = l;
edges[j] = etable[BM_elem_index_get(l->e)];
}
v = vtable[BM_elem_index_get(loops[0]->v)];
v2 = vtable[BM_elem_index_get(loops[1]->v)];
if (!bmesh_verts_in_edge(v, v2, edges[0])) {
v = vtable[BM_elem_index_get(loops[BLI_array_count(loops) - 1]->v)];
v2 = vtable[BM_elem_index_get(loops[0]->v)];
}
f2 = BM_face_create_ngon(bm, v, v2, edges, f->len, FALSE);
if (!f2)
continue;
/* use totface incase adding some faces fails */
BM_elem_index_set(f2, (bm->totface - 1)); /* set_inline */
ftable[i] = f2;
BM_elem_attrs_copy(bmold, bm, f, f2);
copy_v3_v3(f2->no, f->no);
l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f2);
for (j = 0; j < f->len; j++, l = BM_iter_step(&liter)) {
BM_elem_attrs_copy(bmold, bm, loops[j], l);
}
if (f == bmold->act_face) bm->act_face = f2;
}
bmold->elem_index_dirty &= ~BM_FACE;
bm->elem_index_dirty &= ~BM_FACE;
/* safety check */
BLI_assert(i == bmold->totface);
/* copy over edit selection history */
for (ese = bmold->selected.first; ese; ese = ese->next) {
void *ele = NULL;
if (ese->htype == BM_VERT)
ele = vtable[BM_elem_index_get(ese->data)];
else if (ese->htype == BM_EDGE)
ele = etable[BM_elem_index_get(ese->data)];
else if (ese->htype == BM_FACE) {
ele = ftable[BM_elem_index_get(ese->data)];
}
else {
BLI_assert(0);
}
if (ele)
BM_select_history_store(bm, ele);
}
MEM_freeN(etable);
MEM_freeN(vtable);
MEM_freeN(ftable);
BLI_array_free(loops);
BLI_array_free(edges);
return bm;
}
/* ME -> BM */
char BM_vert_flag_from_mflag(const char meflag)
{
return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0)
);
}
char BM_edge_flag_from_mflag(const short meflag)
{
return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
((meflag & ME_SEAM) ? BM_ELEM_SEAM : 0) |
((meflag & ME_SHARP) == 0 ? BM_ELEM_SMOOTH : 0) | /* invert */
((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
((meflag & ME_FREESTYLE_EDGE) ? BM_ELEM_FREESTYLE : 0)
);
}
char BM_face_flag_from_mflag(const char meflag)
{
return ( ((meflag & ME_FACE_SEL) ? BM_ELEM_SELECT : 0) |
((meflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) |
((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
((meflag & ME_FREESTYLE_FACE) ? BM_ELEM_FREESTYLE : 0)
);
}
/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *eve)
{
const char hflag = eve->head.hflag;
return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0)
);
}
short BM_edge_flag_to_mflag(BMEdge *eed)
{
const char hflag = eed->head.hflag;
return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) |
((hflag & BM_ELEM_SMOOTH) == 0 ? ME_SHARP : 0) |
((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_EDGE : 0) |
((BM_edge_is_wire(NULL, eed)) ? ME_LOOSEEDGE : 0) | /* not typical */
(ME_EDGEDRAW | ME_EDGERENDER)
);
}
char BM_face_flag_to_mflag(BMFace *efa)
{
const char hflag = efa->head.hflag;
return ( ((hflag & BM_ELEM_SELECT) ? ME_FACE_SEL : 0) |
((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0) |
((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_FACE : 0)
);
}

@ -0,0 +1,71 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_inline.c
* \ingroup bmesh
*
* BM Inline functions.
*/
#ifndef __BMESH_INLINE_C__
#define __BMESH_INLINE_C__
#include "bmesh.h"
BM_INLINE char BM_elem_flag_test(const void *element, const char hflag)
{
return ((const BMHeader *)element)->hflag & hflag;
}
BM_INLINE void BM_elem_flag_enable(void *element, const char hflag)
{
((BMHeader *)element)->hflag |= hflag;
}
BM_INLINE void BM_elem_flag_disable(void *element, const char hflag)
{
((BMHeader *)element)->hflag &= ~hflag;
}
BM_INLINE void BM_elem_flag_toggle(void *element, const char hflag)
{
((BMHeader *)element)->hflag ^= hflag;
}
BM_INLINE void BM_elem_flag_merge(void *element_a, void *element_b)
{
((BMHeader *)element_a)->hflag =
((BMHeader *)element_b)->hflag = (((BMHeader *)element_a)->hflag |
((BMHeader *)element_b)->hflag);
}
BM_INLINE void BM_elem_index_set(void *element, const int index)
{
((BMHeader *)element)->index = index;
}
BM_INLINE int BM_elem_index_get(const void *element)
{
return ((BMHeader *)element)->index;
}
#endif /* __BMESH_INLINE_C__ */

@ -0,0 +1,984 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_interp.c
* \ingroup bmesh
*
* Functions for interpolating data across the surface of a mesh.
*/
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
#include "BLI_array.h"
#include "BLI_math.h"
#include "bmesh.h"
#include "bmesh_private.h"
/**
* bmesh_data_interp_from_verts
*
* Interpolates per-vertex data from two sources to a target.
*/
void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac)
{
if (v1->head.data && v2->head.data) {
/* first see if we can avoid interpolation */
if (fac <= 0.0f) {
if (v1 == v) {
/* do nothing */
}
else {
CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, v1->head.data, &v->head.data);
}
}
else if (fac >= 1.0f) {
if (v2 == v) {
/* do nothing */
}
else {
CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, v2->head.data, &v->head.data);
}
}
else {
void *src[2];
float w[2];
src[0] = v1->head.data;
src[1] = v2->head.data;
w[0] = 1.0f-fac;
w[1] = fac;
CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data);
}
}
}
/*
* BM Data Vert Average
*
* Sets all the customdata (e.g. vert, loop) associated with a vert
* to the average of the face regions surrounding it.
*/
static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNUSED(f))
{
// BMIter iter;
}
/**
* bmesh_data_facevert_edgeinterp
*
* Walks around the faces of an edge and interpolates the per-face-edge
* data between two sources to a target.
*
* Returns -
* Nothing
*/
void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *UNUSED(v2), BMVert *v, BMEdge *e1, const float fac)
{
void *src[2];
float w[2];
BMLoop *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
BMLoop *l_iter = NULL;
if (!e1->l) {
return;
}
w[1] = 1.0f - fac;
w[0] = fac;
l_iter = e1->l;
do {
if (l_iter->v == v1) {
v1loop = l_iter;
vloop = v1loop->next;
v2loop = vloop->next;
}
else if (l_iter->v == v) {
v1loop = l_iter->next;
vloop = l_iter;
v2loop = l_iter->prev;
}
if (!v1loop || !v2loop)
return;
src[0] = v1loop->head.data;
src[1] = v2loop->head.data;
CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, vloop->head.data);
} while ((l_iter = l_iter->radial_next) != e1->l);
}
void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex,
BMFace *f, int numTex, int numCol)
{
BMLoop *l;
BMIter iter;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j;
for (i = 0; i < numTex; i++) {
texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
ME_MTEXFACE_CPY(texface, texpoly);
j = 0;
BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
copy_v2_v2(texface->uv[j], mloopuv->uv);
j++;
}
}
for (i = 0; i < numCol; i++) {
mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
j = 0;
BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
mcol[j].r = mloopcol->r;
mcol[j].g = mloopcol->g;
mcol[j].b = mloopcol->b;
mcol[j].a = mloopcol->a;
j++;
}
}
}
/**
* BM_data_interp_from_face
*
* projects target onto source, and pulls interpolated customdata from
* source.
*
* Returns -
* Nothing
*/
void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
{
BMLoop *l_iter;
BMLoop *l_first;
void **blocks = NULL;
float (*cos)[3] = NULL, *w = NULL;
BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
int i;
BM_elem_attrs_copy(bm, bm, source, target);
i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
do {
copy_v3_v3(cos[i], l_iter->v->co);
blocks[i] = l_iter->head.data;
i++;
} while ((l_iter = l_iter->next) != l_first);
i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(target);
do {
interp_weights_poly_v3(w, cos, source->len, l_iter->v->co);
CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, l_iter->head.data);
i++;
} while ((l_iter = l_iter->next) != l_first);
BLI_array_fixedstack_free(cos);
BLI_array_fixedstack_free(w);
BLI_array_fixedstack_free(blocks);
}
/* some math stuff for dealing with doubles, put here to
* avoid merge errors - joeedh */
#define VECMUL(a, b) (((a)[0] = (a)[0] * (b)), ((a)[1] = (a)[1] * (b)), ((a)[2] = (a)[2] * (b)))
#define VECADD2(a, b) (((a)[0] = (a)[0] + (b)[0]), ((a)[1] = (a)[1] + (b)[1]), ((a)[2] = (a)[2] + (b)[2]))
#define VECSUB2(a, b) (((a)[0] = (a)[0] - (b)[0]), ((a)[1] = (a)[1] - (b)[1]), ((a)[2] = (a)[2] - (b)[2]))
/* find closest point to p on line through l1, l2 and return lambda,
* where (0 <= lambda <= 1) when cp is in the line segement l1, l2
*/
static double closest_to_line_v3_d(double cp[3], const double p[3], const double l1[3], const double l2[3])
{
double h[3], u[3], lambda;
VECSUB(u, l2, l1);
VECSUB(h, p, l1);
lambda = INPR(u, h) / INPR(u, u);
cp[0] = l1[0] + u[0] * lambda;
cp[1] = l1[1] + u[1] * lambda;
cp[2] = l1[2] + u[2] * lambda;
return lambda;
}
/* point closest to v1 on line v2-v3 in 3D */
static void UNUSED_FUNCTION(closest_to_line_segment_v3_d)(double *closest, double v1[3], double v2[3], double v3[3])
{
double lambda, cp[3];
lambda = closest_to_line_v3_d(cp, v1, v2, v3);
if (lambda <= 0.0) {
VECCOPY(closest, v2);
}
else if (lambda >= 1.0) {
VECCOPY(closest, v3);
}
else {
VECCOPY(closest, cp);
}
}
static double UNUSED_FUNCTION(len_v3_d)(const double a[3])
{
return sqrt(INPR(a, a));
}
static double UNUSED_FUNCTION(len_v3v3_d)(const double a[3], const double b[3])
{
double d[3];
VECSUB(d, b, a);
return sqrt(INPR(d, d));
}
static void cent_quad_v3_d(double *cent, double *v1, double *v2, double *v3, double *v4)
{
cent[0] = 0.25 * (v1[0] + v2[0] + v3[0] + v4[0]);
cent[1] = 0.25 * (v1[1] + v2[1] + v3[1] + v4[1]);
cent[2] = 0.25 * (v1[2] + v2[2] + v3[2] + v4[2]);
}
static void UNUSED_FUNCTION(cent_tri_v3_d)(double *cent, double *v1, double *v2, double *v3)
{
cent[0] = (1.0 / 3.0) * (v1[0] + v2[0] + v3[0]);
cent[1] = (1.0 / 3.0) * (v1[1] + v2[1] + v3[1]);
cent[2] = (1.0 / 3.0) * (v1[2] + v2[2] + v3[2]);
}
static void UNUSED_FUNCTION(cross_v3_v3v3_d)(double r[3], const double a[3], const double b[3])
{
r[0] = a[1] * b[2] - a[2] * b[1];
r[1] = a[2] * b[0] - a[0] * b[2];
r[2] = a[0] * b[1] - a[1] * b[0];
}
/* distance v1 to line-piece v2-v3 */
static double UNUSED_FUNCTION(dist_to_line_segment_v2_d)(double v1[3], double v2[3], double v3[3])
{
double labda, rc[2], pt[2], len;
rc[0] = v3[0] - v2[0];
rc[1] = v3[1] - v2[1];
len = rc[0] * rc[0] + rc[1] * rc[1];
if (len == 0.0) {
rc[0] = v1[0] - v2[0];
rc[1] = v1[1] - v2[1];
return sqrt(rc[0] * rc[0] + rc[1] * rc[1]);
}
labda = (rc[0] * (v1[0] - v2[0]) + rc[1] * (v1[1] - v2[1])) / len;
if (labda <= 0.0) {
pt[0] = v2[0];
pt[1] = v2[1];
}
else if (labda >= 1.0) {
pt[0] = v3[0];
pt[1] = v3[1];
}
else {
pt[0] = labda * rc[0] + v2[0];
pt[1] = labda * rc[1] + v2[1];
}
rc[0] = pt[0] - v1[0];
rc[1] = pt[1] - v1[1];
return sqrt(rc[0] * rc[0] + rc[1] * rc[1]);
}
MINLINE double line_point_side_v2_d(const double *l1, const double *l2, const double *pt)
{
return ((l1[0] - pt[0]) * (l2[1] - pt[1])) -
((l2[0] - pt[0]) * (l1[1] - pt[1]));
}
/* point in quad - only convex quads */
static int isect_point_quad_v2_d(double pt[2], double v1[2], double v2[2], double v3[2], double v4[2])
{
if (line_point_side_v2_d(v1, v2, pt) >= 0.0) {
if (line_point_side_v2_d(v2, v3, pt) >= 0.0) {
if (line_point_side_v2_d(v3, v4, pt) >= 0.0) {
if (line_point_side_v2_d(v4, v1, pt) >= 0.0) {
return 1;
}
}
}
}
else {
if (! (line_point_side_v2_d(v2, v3, pt) >= 0.0)) {
if (! (line_point_side_v2_d(v3, v4, pt) >= 0.0)) {
if (! (line_point_side_v2_d(v4, v1, pt) >= 0.0)) {
return -1;
}
}
}
}
return 0;
}
/***** multires interpolation*****
*
* mdisps is a grid of displacements, ordered thus:
*
* v1/center----v4/next -> x
* | |
* | |
* v2/prev------v3/cur
* |
* V
* y
*/
static int compute_mdisp_quad(BMLoop *l, double v1[3], double v2[3], double v3[3], double v4[3],
double e1[3], double e2[3])
{
double cent[3] = {0.0, 0.0, 0.0}, n[3], p[3];
BMLoop *l_first;
BMLoop *l_iter;
/* computer center */
l_iter = l_first = BM_FACE_FIRST_LOOP(l->f);
do {
cent[0] += (double)l_iter->v->co[0];
cent[1] += (double)l_iter->v->co[1];
cent[2] += (double)l_iter->v->co[2];
} while ((l_iter = l_iter->next) != l_first);
VECMUL(cent, (1.0 / (double)l->f->len));
VECADD(p, l->prev->v->co, l->v->co);
VECMUL(p, 0.5);
VECADD(n, l->next->v->co, l->v->co);
VECMUL(n, 0.5);
VECCOPY(v1, cent);
VECCOPY(v2, p);
VECCOPY(v3, l->v->co);
VECCOPY(v4, n);
VECSUB(e1, v2, v1);
VECSUB(e2, v3, v4);
return 1;
}
/* funnily enough, I think this is identical to face_to_crn_interp, heh */
static double quad_coord(double aa[3], double bb[3], double cc[3], double dd[3], int a1, int a2)
{
double x, y, z, f1;
x = aa[a1] * cc[a2] - cc[a1] * aa[a2];
y = aa[a1] * dd[a2] + bb[a1] * cc[a2] - cc[a1] * bb[a2] - dd[a1] * aa[a2];
z = bb[a1] * dd[a2] - dd[a1] * bb[a2];
if (fabs(2 * (x - y + z)) > DBL_EPSILON * 10.0) {
double f2;
f1 = (sqrt(y * y - 4.0 * x * z) - y + 2.0 * z) / (2.0 * (x - y + z));
f2 = (-sqrt(y * y - 4.0 * x * z) - y + 2.0 * z) / (2.0 * (x - y + z));
f1 = fabs(f1);
f2 = fabs(f2);
f1 = MIN2(f1, f2);
CLAMP(f1, 0.0, 1.0 + DBL_EPSILON);
}
else {
f1 = -z / (y - 2 * z);
CLAMP(f1, 0.0, 1.0 + DBL_EPSILON);
if (isnan(f1) || f1 > 1.0 || f1 < 0.0) {
int i;
for (i = 0; i < 2; i++) {
if (fabsf(aa[i]) < FLT_EPSILON * 100)
return aa[(i + 1) % 2] / fabs(bb[(i + 1) % 2] - aa[(i + 1) % 2]);
if (fabsf(cc[i]) < FLT_EPSILON * 100)
return cc[(i + 1) % 2] / fabs(dd[(i + 1) % 2] - cc[(i + 1) % 2]);
}
}
}
return f1;
}
static int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], double v4[3],
double p[3], float n[3])
{
float projverts[5][3], n2[3];
double dprojverts[4][3], origin[3] = {0.0f, 0.0f, 0.0f};
int i;
/* project points into 2d along normal */
VECCOPY(projverts[0], v1);
VECCOPY(projverts[1], v2);
VECCOPY(projverts[2], v3);
VECCOPY(projverts[3], v4);
VECCOPY(projverts[4], p);
normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
if (INPR(n, n2) < -FLT_EPSILON) {
return 0;
}
/* rotate */
poly_rotate_plane(n, projverts, 5);
/* flatten */
for (i = 0; i < 5; i++) {
projverts[i][2] = 0.0f;
}
/* subtract origin */
for (i = 0; i < 4; i++) {
VECSUB2(projverts[i], projverts[4]);
}
VECCOPY(dprojverts[0], projverts[0]);
VECCOPY(dprojverts[1], projverts[1]);
VECCOPY(dprojverts[2], projverts[2]);
VECCOPY(dprojverts[3], projverts[3]);
if (!isect_point_quad_v2_d(origin, dprojverts[0], dprojverts[1], dprojverts[2], dprojverts[3])) {
return 0;
}
*y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
*x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
return 1;
}
/* tl is loop to project onto, l is loop whose internal displacement, co, is being
* projected. x and y are location in loop's mdisps grid of point co. */
static int mdisp_in_mdispquad(BMesh *bm, BMLoop *l, BMLoop *tl, double p[3], double *x, double *y, int res)
{
double v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
double eps = FLT_EPSILON * 4000;
if (len_v3(l->v->no) == 0.0f)
BM_vert_normal_update_all(bm, l->v);
if (len_v3(tl->v->no) == 0.0f)
BM_vert_normal_update_all(bm, tl->v);
compute_mdisp_quad(tl, v1, v2, v3, v4, e1, e2);
/* expand quad a bit */
cent_quad_v3_d(c, v1, v2, v3, v4);
VECSUB2(v1, c); VECSUB2(v2, c);
VECSUB2(v3, c); VECSUB2(v4, c);
VECMUL(v1, 1.0 + eps); VECMUL(v2, 1.0 + eps);
VECMUL(v3, 1.0 + eps); VECMUL(v4, 1.0 + eps);
VECADD2(v1, c); VECADD2(v2, c);
VECADD2(v3, c); VECADD2(v4, c);
if (!quad_co(x, y, v1, v2, v3, v4, p, l->v->no))
return 0;
*x *= res - 1;
*y *= res - 1;
return 1;
}
static void bmesh_loop_interp_mdisps(BMesh *bm, BMLoop *target, BMFace *source)
{
MDisps *mdisps;
BMLoop *l_iter;
BMLoop *l_first;
double x, y, d, v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3];
int ix, iy, res;
/* ignore 2-edged faces */
if (target->f->len < 3)
return;
if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
return;
mdisps = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
compute_mdisp_quad(target, v1, v2, v3, v4, e1, e2);
/* if no disps data allocate a new grid, the size of the first grid in source. */
if (!mdisps->totdisp) {
MDisps *md2 = CustomData_bmesh_get(&bm->ldata, BM_FACE_FIRST_LOOP(source)->head.data, CD_MDISPS);
mdisps->totdisp = md2->totdisp;
if (mdisps->totdisp) {
mdisps->disps = MEM_callocN(sizeof(float) * 3 * mdisps->totdisp,
"mdisp->disps in bmesh_loop_intern_mdisps");
}
else {
return;
}
}
res = (int)sqrt(mdisps->totdisp);
d = 1.0 / (double)(res - 1);
for (x = 0.0f, ix = 0; ix < res; x += d, ix++) {
for (y = 0.0f, iy = 0; iy < res; y += d, iy++) {
double co1[3], co2[3], co[3];
/* double xx, yy; */ /* UNUSED */
VECCOPY(co1, e1);
/* if (!iy) yy = y + (double)FLT_EPSILON * 20; */
/* else yy = y - (double)FLT_EPSILON * 20; */
VECMUL(co1, y);
VECADD2(co1, v1);
VECCOPY(co2, e2);
VECMUL(co2, y);
VECADD2(co2, v4);
/* if (!ix) xx = x + (double)FLT_EPSILON * 20; */ /* UNUSED */
/* else xx = x - (double)FLT_EPSILON * 20; */ /* UNUSED */
VECSUB(co, co2, co1);
VECMUL(co, x);
VECADD2(co, co1);
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
do {
double x2, y2;
MDisps *md1, *md2;
md1 = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
md2 = CustomData_bmesh_get(&bm->ldata, l_iter->head.data, CD_MDISPS);
if (mdisp_in_mdispquad(bm, target, l_iter, co, &x2, &y2, res)) {
/* int ix2 = (int)x2; */ /* UNUSED */
/* int iy2 = (int)y2; */ /* UNUSED */
old_mdisps_bilinear(md1->disps[iy * res + ix], md2->disps, res, (float)x2, (float)y2);
}
} while ((l_iter = l_iter->next) != l_first);
}
}
}
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
{
BMLoop *l;
BMIter liter;
if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
return;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
MDisps *mdp = CustomData_bmesh_get(&bm->ldata, l->prev->head.data, CD_MDISPS);
MDisps *mdl = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
MDisps *mdn = CustomData_bmesh_get(&bm->ldata, l->next->head.data, CD_MDISPS);
float co1[3];
int sides;
int y;
/*
* mdisps is a grid of displacements, ordered thus:
*
* v4/next
* |
* | v1/cent-----mid2 ---> x
* | | |
* | | |
* v2/prev---mid1-----v3/cur
* |
* V
* y
*/
sides = (int)sqrt(mdp->totdisp);
for (y = 0; y < sides; y++) {
add_v3_v3v3(co1, mdn->disps[y * sides], mdl->disps[y]);
mul_v3_fl(co1, 0.5);
copy_v3_v3(mdn->disps[y * sides], co1);
copy_v3_v3(mdl->disps[y], co1);
}
}
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
MDisps *mdl1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
MDisps *mdl2;
float co1[3], co2[3], co[3];
int sides;
int y;
/*
* mdisps is a grid of displacements, ordered thus:
*
* v4/next
* |
* | v1/cent-----mid2 ---> x
* | | |
* | | |
* v2/prev---mid1-----v3/cur
* |
* V
* y
*/
if (l->radial_next == l)
continue;
if (l->radial_next->v == l->v)
mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->head.data, CD_MDISPS);
else
mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->next->head.data, CD_MDISPS);
sides = (int)sqrt(mdl1->totdisp);
for (y = 0; y < sides; y++) {
int a1, a2, o1, o2;
if (l->v != l->radial_next->v) {
a1 = sides * y + sides - 2;
a2 = (sides - 2) * sides + y;
o1 = sides * y + sides - 1;
o2 = (sides - 1) * sides + y;
}
else {
a1 = sides * y + sides - 2;
a2 = sides * y + sides - 2;
o1 = sides * y + sides - 1;
o2 = sides * y + sides - 1;
}
/* magic blending numbers, hardcoded! */
add_v3_v3v3(co1, mdl1->disps[a1], mdl2->disps[a2]);
mul_v3_fl(co1, 0.18);
add_v3_v3v3(co2, mdl1->disps[o1], mdl2->disps[o2]);
mul_v3_fl(co2, 0.32);
add_v3_v3v3(co, co1, co2);
copy_v3_v3(mdl1->disps[o1], co);
copy_v3_v3(mdl2->disps[o2], co);
}
}
}
void BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source)
{
bmesh_loop_interp_mdisps(bm, target, source);
}
void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
int do_vertex, int do_multires)
{
BMLoop *l_iter;
BMLoop *l_first;
void **blocks = NULL;
void **vblocks = NULL;
float (*cos)[3] = NULL, co[3], *w = NULL;
float cent[3] = {0.0f, 0.0f, 0.0f};
BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(vblocks, BM_NGON_STACK_SIZE, do_vertex ? source->len : 0, __func__);
int i, ax, ay;
BM_elem_attrs_copy(bm, bm, source, target->f);
i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
do {
copy_v3_v3(cos[i], l_iter->v->co);
add_v3_v3(cent, cos[i]);
w[i] = 0.0f;
blocks[i] = l_iter->head.data;
if (do_vertex) {
vblocks[i] = l_iter->v->head.data;
}
i++;
} while ((l_iter = l_iter->next) != l_first);
/* find best projection of face XY, XZ or YZ: barycentric weights of
* the 2d projected coords are the same and faster to compute */
axis_dominant_v3(&ax, &ay, source->no);
/* scale source face coordinates a bit, so points sitting directonly on an
* edge will work. */
mul_v3_fl(cent, 1.0f / (float)source->len);
for (i = 0; i < source->len; i++) {
float vec[3], tmp[3];
sub_v3_v3v3(vec, cent, cos[i]);
mul_v3_fl(vec, 0.001f);
add_v3_v3(cos[i], vec);
copy_v3_v3(tmp, cos[i]);
cos[i][0] = tmp[ax];
cos[i][1] = tmp[ay];
cos[i][2] = 0.0;
}
/* interpolate */
co[0] = target->v->co[ax];
co[1] = target->v->co[ay];
co[2] = 0.0f;
interp_weights_poly_v3(w, cos, source->len, co);
CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data);
if (do_vertex) {
CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, source->len, target->v->head.data);
BLI_array_fixedstack_free(vblocks);
}
BLI_array_fixedstack_free(cos);
BLI_array_fixedstack_free(w);
BLI_array_fixedstack_free(blocks);
if (do_multires) {
if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
bmesh_loop_interp_mdisps(bm, target, source);
}
}
}
void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source)
{
BMLoop *l_iter;
BMLoop *l_first;
void **blocks = NULL;
float (*cos)[3] = NULL, *w = NULL;
float cent[3] = {0.0f, 0.0f, 0.0f};
BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
int i;
i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(source);
do {
copy_v3_v3(cos[i], l_iter->v->co);
add_v3_v3(cent, cos[i]);
w[i] = 0.0f;
blocks[i] = l_iter->v->head.data;
i++;
} while ((l_iter = l_iter->next) != l_first);
/* scale source face coordinates a bit, so points sitting directonly on an
* edge will work. */
mul_v3_fl(cent, 1.0f / (float)source->len);
for (i = 0; i < source->len; i++) {
float vec[3];
sub_v3_v3v3(vec, cent, cos[i]);
mul_v3_fl(vec, 0.01);
add_v3_v3(cos[i], vec);
}
/* interpolate */
interp_weights_poly_v3(w, cos, source->len, v->co);
CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, source->len, v->head.data);
BLI_array_fixedstack_free(cos);
BLI_array_fixedstack_free(w);
BLI_array_fixedstack_free(blocks);
}
static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
{
BMIter iter;
BLI_mempool *oldpool = olddata->pool;
void *block;
CustomData_bmesh_init_pool(data, data == &bm->ldata ? 2048 : 512);
if (data == &bm->vdata) {
BMVert *eve;
BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
block = NULL;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
CustomData_bmesh_free_block(olddata, &eve->head.data);
eve->head.data = block;
}
}
else if (data == &bm->edata) {
BMEdge *eed;
BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
block = NULL;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
CustomData_bmesh_free_block(olddata, &eed->head.data);
eed->head.data = block;
}
}
else if (data == &bm->pdata || data == &bm->ldata) {
BMIter liter;
BMFace *efa;
BMLoop *l;
BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (data == &bm->pdata) {
block = NULL;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
CustomData_bmesh_free_block(olddata, &efa->head.data);
efa->head.data = block;
}
if (data == &bm->ldata) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
block = NULL;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
CustomData_bmesh_free_block(olddata, &l->head.data);
l->head.data = block;
}
}
}
}
if (oldpool) {
/* this should never happen but can when dissolve fails - [#28960] */
BLI_assert(data->pool != oldpool);
BLI_mempool_destroy(oldpool);
}
}
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
{
CustomData olddata;
olddata = *data;
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
/* the pool is now owned by olddata and must not be shared */
data->pool = NULL;
CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
update_data_blocks(bm, &olddata, data);
if (olddata.layers) MEM_freeN(olddata.layers);
}
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
{
CustomData olddata;
olddata = *data;
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
/* the pool is now owned by olddata and must not be shared */
data->pool = NULL;
CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
update_data_blocks(bm, &olddata, data);
if (olddata.layers) MEM_freeN(olddata.layers);
}
void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
{
CustomData olddata;
olddata = *data;
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
/* the pool is now owned by olddata and must not be shared */
data->pool = NULL;
CustomData_free_layer_active(data, type, 0);
update_data_blocks(bm, &olddata, data);
if (olddata.layers) MEM_freeN(olddata.layers);
}
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
{
CustomData olddata;
olddata = *data;
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
/* the pool is now owned by olddata and must not be shared */
data->pool = NULL;
CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
update_data_blocks(bm, &olddata, data);
if (olddata.layers) MEM_freeN(olddata.layers);
}
float BM_elem_float_data_get(CustomData *cd, void *element, int type)
{
float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
return f ? *f : 0.0f;
}
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
{
float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
if (f) *f = val;
}

@ -0,0 +1,417 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_iterators.c
* \ingroup bmesh
*
* Functions to abstract looping over bmesh data structures.
*
* See: bmesh_iterators_inlin.c too, some functions are here for speed reasons.
*/
#include "bmesh.h"
#include "bmesh_private.h"
/*
* note, we have BM_vert_at_index/BM_edge_at_index/BM_face_at_index for arrays
*/
void *BM_iter_at_index(struct BMesh *bm, const char itype, void *data, int index)
{
BMIter iter;
void *val;
int i;
/* sanity check */
if (index < 0) {
return NULL;
}
val = BM_iter_new(&iter, bm, itype, data);
i = 0;
while (i < index) {
val = BM_iter_step(&iter);
i++;
}
return val;
}
/*
* ITERATOR AS ARRAY
*
* Sometimes its convenient to get the iterator as an array
* to avoid multiple calls to BM_iter_at_index.
*/
int BM_iter_as_array(struct BMesh *bm, const char type, void *data, void **array, const int len)
{
int i = 0;
/* sanity check */
if (len > 0) {
BMIter iter;
void *val;
BM_ITER(val, &iter, bm, type, data) {
array[i] = val;
i++;
if (i == len) {
return len;
}
}
}
return i;
}
/*
* INIT ITERATOR
*
* Clears the internal state of an iterator
* For begin() callbacks.
*
*/
static void init_iterator(BMIter *iter)
{
iter->firstvert = iter->nextvert = NULL;
iter->firstedge = iter->nextedge = NULL;
iter->firstloop = iter->nextloop = NULL;
iter->firstpoly = iter->nextpoly = NULL;
iter->ldata = NULL;
}
/*
* Notes on iterator implementation:
*
* Iterators keep track of the next element
* in a sequence. When a step() callback is
* invoked the current value of 'next' is stored
* to be returned later and the next variable is
* incremented.
*
* When the end of a sequence is
* reached, next should always equal NULL
*
* The 'bmiter__' prefix is used because these are used in
* bmesh_iterators_inine.c but should otherwise be seen as
* private.
*/
/*
* VERT OF MESH CALLBACKS
*
*/
void bmiter__vert_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter);
}
void *bmiter__vert_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
void bmiter__edge_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->epool, &iter->pooliter);
}
void *bmiter__edge_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
void bmiter__face_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter);
}
void *bmiter__face_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
/*
* EDGE OF VERT CALLBACKS
*
*/
void bmiter__edge_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
if (iter->vdata->e) {
iter->firstedge = iter->vdata->e;
iter->nextedge = iter->vdata->e;
}
}
void *bmiter__edge_of_vert_step(BMIter *iter)
{
BMEdge *current = iter->nextedge;
if (iter->nextedge)
iter->nextedge = bmesh_disk_nextedge(iter->nextedge, iter->vdata);
if (iter->nextedge == iter->firstedge) iter->nextedge = NULL;
return current;
}
/*
* FACE OF VERT CALLBACKS
*
*/
void bmiter__face_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
iter->count = 0;
if (iter->vdata->e)
iter->count = bmesh_disk_count_facevert(iter->vdata);
if (iter->count) {
iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->e, iter->vdata);
iter->nextedge = iter->firstedge;
iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->l, iter->vdata);
iter->nextloop = iter->firstloop;
}
}
void *bmiter__face_of_vert_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->count && iter->nextloop) {
iter->count--;
iter->nextloop = bmesh_radial_find_next_facevert(iter->nextloop, iter->vdata);
if (iter->nextloop == iter->firstloop) {
iter->nextedge = bmesh_disk_find_next_faceedge(iter->nextedge, iter->vdata);
iter->firstloop = bmesh_radial_find_first_facevert(iter->nextedge->l, iter->vdata);
iter->nextloop = iter->firstloop;
}
}
if (!iter->count) iter->nextloop = NULL;
return current ? current->f : NULL;
}
/*
* LOOP OF VERT CALLBACKS
*
*/
void bmiter__loop_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
iter->count = 0;
if (iter->vdata->e)
iter->count = bmesh_disk_count_facevert(iter->vdata);
if (iter->count) {
iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->e, iter->vdata);
iter->nextedge = iter->firstedge;
iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->l, iter->vdata);
iter->nextloop = iter->firstloop;
}
}
void *bmiter__loop_of_vert_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->count) {
iter->count--;
iter->nextloop = bmesh_radial_find_next_facevert(iter->nextloop, iter->vdata);
if (iter->nextloop == iter->firstloop) {
iter->nextedge = bmesh_disk_find_next_faceedge(iter->nextedge, iter->vdata);
iter->firstloop = bmesh_radial_find_first_facevert(iter->nextedge->l, iter->vdata);
iter->nextloop = iter->firstloop;
}
}
if (!iter->count) iter->nextloop = NULL;
if (current) {
return current;
}
return NULL;
}
void bmiter__loops_of_edge_begin(BMIter *iter)
{
BMLoop *l;
l = iter->edata->l;
/* note sure why this sets ldata ... */
init_iterator(iter);
iter->firstloop = iter->nextloop = l;
}
void *bmiter__loops_of_edge_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop)
iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
if (iter->nextloop == iter->firstloop)
iter->nextloop = NULL;
if (current) {
return current;
}
return NULL;
}
void bmiter__loops_of_loop_begin(BMIter *iter)
{
BMLoop *l;
l = iter->ldata;
/* note sure why this sets ldata ... */
init_iterator(iter);
iter->firstloop = l;
iter->nextloop = bmesh_radial_nextloop(iter->firstloop);
if (iter->nextloop == iter->firstloop)
iter->nextloop = NULL;
}
void *bmiter__loops_of_loop_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
if (current) {
return current;
}
return NULL;
}
/*
* FACE OF EDGE CALLBACKS
*
*/
void bmiter__face_of_edge_begin(BMIter *iter)
{
init_iterator(iter);
if (iter->edata->l) {
iter->firstloop = iter->edata->l;
iter->nextloop = iter->edata->l;
}
}
void *bmiter__face_of_edge_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
return current ? current->f : NULL;
}
/*
* VERT OF FACE CALLBACKS
*
*/
void bmiter__vert_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__vert_of_face_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop) iter->nextloop = iter->nextloop->next;
if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
return current ? current->v : NULL;
}
/*
* EDGE OF FACE CALLBACKS
*
*/
void bmiter__edge_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__edge_of_face_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop) iter->nextloop = iter->nextloop->next;
if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
return current ? current->e : NULL;
}
/*
* LOOP OF FACE CALLBACKS
*
*/
void bmiter__loop_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__loop_of_face_step(BMIter *iter)
{
BMLoop *current = iter->nextloop;
if (iter->nextloop) iter->nextloop = iter->nextloop->next;
if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
return current;
}

@ -0,0 +1,160 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_iterators_inline.c
* \ingroup bmesh
*
* BMesh inline iterator functions.
*/
#ifndef __BMESH_ITERATORS_INLINE_C__
#define __BMESH_ITERATORS_INLINE_C__
#include "bmesh.h"
/* inline here optimizes out the switch statement when called with
* constant values (which is very common), nicer for loop-in-loop situations */
/*
* BMESH ITERATOR STEP
*
* Calls an iterators step fucntion to return
* the next element.
*/
BM_INLINE void *BM_iter_step(BMIter *iter)
{
return iter->step(iter);
}
/*
* BMESH ITERATOR INIT
*
* Takes a bmesh iterator structure and fills
* it with the appropriate function pointers based
* upon its type and then calls BMeshIter_step()
* to return the first element of the iterator.
*
*/
BM_INLINE void *BM_iter_new(BMIter *iter, BMesh *bm, const char itype, void *data)
{
/* int argtype; */
iter->itype = itype;
iter->bm = bm;
/* inlining optimizes out this switch when called with the defined type */
switch (itype) {
case BM_VERTS_OF_MESH:
iter->begin = bmiter__vert_of_mesh_begin;
iter->step = bmiter__vert_of_mesh_step;
break;
case BM_EDGES_OF_MESH:
iter->begin = bmiter__edge_of_mesh_begin;
iter->step = bmiter__edge_of_mesh_step;
break;
case BM_FACES_OF_MESH:
iter->begin = bmiter__face_of_mesh_begin;
iter->step = bmiter__face_of_mesh_step;
break;
case BM_EDGES_OF_VERT:
if (!data)
return NULL;
iter->begin = bmiter__edge_of_vert_begin;
iter->step = bmiter__edge_of_vert_step;
iter->vdata = data;
break;
case BM_FACES_OF_VERT:
if (!data)
return NULL;
iter->begin = bmiter__face_of_vert_begin;
iter->step = bmiter__face_of_vert_step;
iter->vdata = data;
break;
case BM_LOOPS_OF_VERT:
if (!data)
return NULL;
iter->begin = bmiter__loop_of_vert_begin;
iter->step = bmiter__loop_of_vert_step;
iter->vdata = data;
break;
case BM_FACES_OF_EDGE:
if (!data)
return NULL;
iter->begin = bmiter__face_of_edge_begin;
iter->step = bmiter__face_of_edge_step;
iter->edata = data;
break;
case BM_VERTS_OF_FACE:
if (!data)
return NULL;
iter->begin = bmiter__vert_of_face_begin;
iter->step = bmiter__vert_of_face_step;
iter->pdata = data;
break;
case BM_EDGES_OF_FACE:
if (!data)
return NULL;
iter->begin = bmiter__edge_of_face_begin;
iter->step = bmiter__edge_of_face_step;
iter->pdata = data;
break;
case BM_LOOPS_OF_FACE:
if (!data)
return NULL;
iter->begin = bmiter__loop_of_face_begin;
iter->step = bmiter__loop_of_face_step;
iter->pdata = data;
break;
case BM_LOOPS_OF_LOOP:
if (!data)
return NULL;
iter->begin = bmiter__loops_of_loop_begin;
iter->step = bmiter__loops_of_loop_step;
iter->ldata = data;
break;
case BM_LOOPS_OF_EDGE:
if (!data)
return NULL;
iter->begin = bmiter__loops_of_edge_begin;
iter->step = bmiter__loops_of_edge_step;
iter->edata = data;
break;
default:
break;
}
iter->begin(iter);
return BM_iter_step(iter);
}
#endif /* __BMESH_ITERATORS_INLINE_C__ */

@ -0,0 +1,910 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_marking.c
* \ingroup bmesh
*
* Selection routines for bmesh structures.
* This is actually all old code ripped from
* editmesh_lib.c and slightly modified to work
* for bmesh's. This also means that it has some
* of the same problems.... something that
* that should be addressed eventually.
*/
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "bmesh.h"
/*
* BMESH SELECTMODE FLUSH
*
* Makes sure to flush selections
* 'upwards' (ie: all verts of an edge
* selects the edge and so on). This
* should only be called by system and not
* tool authors.
*
*/
static void recount_totsels(BMesh *bm)
{
BMIter iter;
BMHeader *ele;
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
BM_FACES_OF_MESH};
int *tots[3];
int i;
/* recount (tot * sel) variables */
bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
tots[0] = &bm->totvertsel;
tots[1] = &bm->totedgesel;
tots[2] = &bm->totfacesel;
for (i = 0; i < 3; i++) {
ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
for ( ; ele; ele = BM_iter_step(&iter)) {
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) *tots[i] += 1;
}
}
}
void BM_mesh_select_mode_flush(BMesh *bm)
{
BMEdge *e;
BMLoop *l_iter;
BMLoop *l_first;
BMFace *f;
BMIter edges;
BMIter faces;
int ok;
if (bm->selectmode & SCE_SELECT_VERTEX) {
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
{
BM_elem_flag_enable(e, BM_ELEM_SELECT);
}
else {
BM_elem_flag_disable(e, BM_ELEM_SELECT);
}
}
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
ok = TRUE;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
ok = FALSE;
break;
}
} while ((l_iter = l_iter->next) != l_first);
}
else {
ok = FALSE;
}
if (ok) {
BM_elem_flag_enable(f, BM_ELEM_SELECT);
}
else {
BM_elem_flag_disable(f, BM_ELEM_SELECT);
}
}
}
else if (bm->selectmode & SCE_SELECT_EDGE) {
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
ok = TRUE;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (!BM_elem_flag_test(&(l_iter->e->head), BM_ELEM_SELECT)) {
ok = FALSE;
break;
}
} while ((l_iter = l_iter->next) != l_first);
}
else {
ok = FALSE;
}
if (ok) {
BM_elem_flag_enable(f, BM_ELEM_SELECT);
}
else {
BM_elem_flag_disable(f, BM_ELEM_SELECT);
}
}
}
/* Remove any deselected elements from the BMEditSelection */
BM_select_history_validate(bm);
recount_totsels(bm);
}
/* BMESH NOTE: matches EM_deselect_flush() behavior from trunk */
void BM_mesh_deselect_flush(BMesh *bm)
{
BMEdge *e;
BMLoop *l_iter;
BMLoop *l_first;
BMFace *f;
BMIter edges;
BMIter faces;
int ok;
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (!(BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
!BM_elem_flag_test(e, BM_ELEM_HIDDEN)))
{
BM_elem_flag_disable(e, BM_ELEM_SELECT);
}
}
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
ok = TRUE;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
ok = FALSE;
break;
}
} while ((l_iter = l_iter->next) != l_first);
}
else {
ok = FALSE;
}
if (ok == FALSE) {
BM_elem_flag_disable(f, BM_ELEM_SELECT);
}
}
/* Remove any deselected elements from the BMEditSelection */
BM_select_history_validate(bm);
recount_totsels(bm);
}
/* BMESH NOTE: matches EM_select_flush() behavior from trunk */
void BM_mesh_select_flush(BMesh *bm)
{
BMEdge *e;
BMLoop *l_iter;
BMLoop *l_first;
BMFace *f;
BMIter edges;
BMIter faces;
int ok;
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
{
BM_elem_flag_enable(e, BM_ELEM_SELECT);
}
}
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
ok = TRUE;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
ok = FALSE;
break;
}
} while ((l_iter = l_iter->next) != l_first);
}
else {
ok = FALSE;
}
if (ok) {
BM_elem_flag_enable(f, BM_ELEM_SELECT);
}
}
recount_totsels(bm);
}
/*
* BMESH SELECT VERT
*
* Changes selection state of a single vertex
* in a mesh
*
*/
void BM_vert_select_set(BMesh *bm, BMVert *v, int select)
{
/* BMIter iter; */
/* BMEdge *e; */
if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
return;
}
if (select) {
if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
bm->totvertsel += 1;
BM_elem_flag_enable(v, BM_ELEM_SELECT);
}
}
else {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
bm->totvertsel -= 1;
BM_elem_flag_disable(v, BM_ELEM_SELECT);
}
}
}
/*
* BMESH SELECT EDGE
*
* Changes selection state of a single edge
* in a mesh.
*
*/
void BM_edge_select_set(BMesh *bm, BMEdge *e, int select)
{
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
return;
}
if (select) {
if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel += 1;
BM_elem_flag_enable(&(e->head), BM_ELEM_SELECT);
BM_elem_select_set(bm, e->v1, TRUE);
BM_elem_select_set(bm, e->v2, TRUE);
}
else {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel -= 1;
BM_elem_flag_disable(&(e->head), BM_ELEM_SELECT);
if ( bm->selectmode == SCE_SELECT_EDGE ||
bm->selectmode == SCE_SELECT_FACE ||
bm->selectmode == (SCE_SELECT_EDGE | SCE_SELECT_FACE))
{
BMIter iter;
BMVert *verts[2] = {e->v1, e->v2};
BMEdge *e2;
int i;
for (i = 0; i < 2; i++) {
int deselect = 1;
for (e2 = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, verts[i]); e2; e2 = BM_iter_step(&iter)) {
if (e2 == e) {
continue;
}
if (BM_elem_flag_test(e2, BM_ELEM_SELECT)) {
deselect = 0;
break;
}
}
if (deselect) BM_vert_select_set(bm, verts[i], FALSE);
}
}
else {
BM_elem_select_set(bm, e->v1, FALSE);
BM_elem_select_set(bm, e->v2, FALSE);
}
}
}
/*
*
* BMESH SELECT FACE
*
* Changes selection state of a single
* face in a mesh.
*
*/
void BM_face_select_set(BMesh *bm, BMFace *f, int select)
{
BMLoop *l_iter;
BMLoop *l_first;
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
return;
}
if (select) {
if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
bm->totfacesel++;
}
BM_elem_flag_enable(&(f->head), BM_ELEM_SELECT);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BM_vert_select_set(bm, l_iter->v, TRUE);
BM_edge_select_set(bm, l_iter->e, TRUE);
} while ((l_iter = l_iter->next) != l_first);
}
else {
BMIter liter;
BMLoop *l;
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) bm->totfacesel -= 1;
BM_elem_flag_disable(&(f->head), BM_ELEM_SELECT);
/* flush down to edges */
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BMIter fiter;
BMFace *f2;
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
if (BM_elem_flag_test(f2, BM_ELEM_SELECT))
break;
}
if (!f2)
{
BM_elem_select_set(bm, l->e, FALSE);
}
}
/* flush down to verts */
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BMIter eiter;
BMEdge *e;
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT))
break;
}
if (!e) {
BM_elem_select_set(bm, l->v, FALSE);
}
}
}
}
/*
* BMESH SELECTMODE SET
*
* Sets the selection mode for the bmesh
*
*/
void BM_select_mode_set(BMesh *bm, int selectmode)
{
BMVert *v;
BMEdge *e;
BMFace *f;
BMIter verts;
BMIter edges;
BMIter faces;
bm->selectmode = selectmode;
if (bm->selectmode & SCE_SELECT_VERTEX) {
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
BM_elem_flag_disable(e, 0);
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces))
BM_elem_flag_disable(f, 0);
BM_mesh_select_mode_flush(bm);
}
else if (bm->selectmode & SCE_SELECT_EDGE) {
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts))
BM_elem_flag_disable(v, 0);
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
if (BM_elem_flag_test(&(e->head), BM_ELEM_SELECT)) {
BM_edge_select_set(bm, e, TRUE);
}
}
BM_mesh_select_mode_flush(bm);
}
else if (bm->selectmode & SCE_SELECT_FACE) {
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
BM_elem_flag_disable(e, 0);
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
if (BM_elem_flag_test(&(f->head), BM_ELEM_SELECT)) {
BM_face_select_set(bm, f, TRUE);
}
}
BM_mesh_select_mode_flush(bm);
}
}
int BM_mesh_count_flag(struct BMesh *bm, const char htype, const char hflag, int respecthide)
{
BMHeader *head;
BMIter iter;
int tot = 0;
if (htype & BM_VERT) {
for (head = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
if (BM_elem_flag_test(head, hflag)) tot++;
}
}
if (htype & BM_EDGE) {
for (head = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
if (BM_elem_flag_test(head, hflag)) tot++;
}
}
if (htype & BM_FACE) {
for (head = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
if (BM_elem_flag_test(head, hflag)) tot++;
}
}
return tot;
}
/* note: by design, this will not touch the editselection history stuff */
void BM_elem_select_set(struct BMesh *bm, void *element, int select)
{
BMHeader *head = element;
if (head->htype == BM_VERT) BM_vert_select_set(bm, (BMVert *)element, select);
else if (head->htype == BM_EDGE) BM_edge_select_set(bm, (BMEdge *)element, select);
else if (head->htype == BM_FACE) BM_face_select_set(bm, (BMFace *)element, select);
}
/* this replaces the active flag used in uv/face mode */
void BM_active_face_set(BMesh *bm, BMFace *efa)
{
bm->act_face = efa;
}
BMFace *BM_active_face_get(BMesh *bm, int sloppy)
{
if (bm->act_face) {
return bm->act_face;
}
else if (sloppy) {
BMIter iter;
BMFace *f = NULL;
BMEditSelection *ese;
/* Find the latest non-hidden face from the BMEditSelection */
ese = bm->selected.last;
for ( ; ese; ese = ese->prev) {
if (ese->htype == BM_FACE) {
f = (BMFace *)ese->data;
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
f = NULL;
}
else {
break;
}
}
}
/* Last attempt: try to find any selected face */
if (f == NULL) {
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
break;
}
}
}
return f; /* can still be null */
}
return NULL;
}
/* Generic way to get data from an EditSelection type
* These functions were written to be used by the Modifier widget
* when in Rotate about active mode, but can be used anywhere.
*
* - EM_editselection_center
* - EM_editselection_normal
* - EM_editselection_plane
*/
void BM_editselection_center(BMesh *bm, float r_center[3], BMEditSelection *ese)
{
if (ese->htype == BM_VERT) {
BMVert *eve = ese->data;
copy_v3_v3(r_center, eve->co);
}
else if (ese->htype == BM_EDGE) {
BMEdge *eed = ese->data;
add_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
mul_v3_fl(r_center, 0.5);
}
else if (ese->htype == BM_FACE) {
BMFace *efa = ese->data;
BM_face_center_bounds_calc(bm, efa, r_center);
}
}
void BM_editselection_normal(float r_normal[3], BMEditSelection *ese)
{
if (ese->htype == BM_VERT) {
BMVert *eve = ese->data;
copy_v3_v3(r_normal, eve->no);
}
else if (ese->htype == BM_EDGE) {
BMEdge *eed = ese->data;
float plane[3]; /* need a plane to correct the normal */
float vec[3]; /* temp vec storage */
add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
/* the 2 vertex normals will be close but not at rightangles to the edge
* for rotate about edge we want them to be at right angles, so we need to
* do some extra colculation to correct the vert normals,
* we need the plane for this */
cross_v3_v3v3(vec, r_normal, plane);
cross_v3_v3v3(r_normal, plane, vec);
normalize_v3(r_normal);
}
else if (ese->htype == BM_FACE) {
BMFace *efa = ese->data;
copy_v3_v3(r_normal, efa->no);
}
}
/* ref - editmesh_lib.cL:EM_editselection_plane() */
/* Calculate a plane that is rightangles to the edge/vert/faces normal
* also make the plane run along an axis that is related to the geometry,
* because this is used for the manipulators Y axis. */
void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese)
{
if (ese->htype == BM_VERT) {
BMVert *eve = ese->data;
float vec[3] = {0.0f, 0.0f, 0.0f};
if (ese->prev) { /* use previously selected data to make a useful vertex plane */
BM_editselection_center(bm, vec, ese->prev);
sub_v3_v3v3(r_plane, vec, eve->co);
}
else {
/* make a fake plane thats at rightangles to the normal
* we cant make a crossvec from a vec thats the same as the vec
* unlikely but possible, so make sure if the normal is (0, 0, 1)
* that vec isnt the same or in the same direction even. */
if (eve->no[0] < 0.5f) vec[0] = 1.0f;
else if (eve->no[1] < 0.5f) vec[1] = 1.0f;
else vec[2] = 1.0f;
cross_v3_v3v3(r_plane, eve->no, vec);
}
}
else if (ese->htype == BM_EDGE) {
BMEdge *eed = ese->data;
/* the plane is simple, it runs along the edge
* however selecting different edges can swap the direction of the y axis.
* this makes it less likely for the y axis of the manipulator
* (running along the edge).. to flip less often.
* at least its more pradictable */
if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
}
else {
sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
}
}
else if (ese->htype == BM_FACE) {
BMFace *efa = ese->data;
float vec[3] = {0.0f, 0.0f, 0.0f};
/* for now, use face normal */
/* make a fake plane thats at rightangles to the normal
* we cant make a crossvec from a vec thats the same as the vec
* unlikely but possible, so make sure if the normal is (0, 0, 1)
* that vec isnt the same or in the same direction even. */
if (efa->len < 3) {
/* crappy fallback method */
if (efa->no[0] < 0.5f) vec[0] = 1.0f;
else if (efa->no[1] < 0.5f) vec[1] = 1.0f;
else vec[2] = 1.0f;
cross_v3_v3v3(r_plane, efa->no, vec);
}
else {
BMVert *verts[4] = {NULL};
BM_iter_as_array(bm, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
if (efa->len == 4) {
float vecA[3], vecB[3];
sub_v3_v3v3(vecA, verts[3]->co, verts[2]->co);
sub_v3_v3v3(vecB, verts[0]->co, verts[1]->co);
add_v3_v3v3(r_plane, vecA, vecB);
sub_v3_v3v3(vecA, verts[0]->co, verts[3]->co);
sub_v3_v3v3(vecB, verts[1]->co, verts[2]->co);
add_v3_v3v3(vec, vecA, vecB);
/* use the biggest edge length */
if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
copy_v3_v3(r_plane, vec);
}
}
else {
/* BMESH_TODO (not urgent, use longest ngon edge for alignment) */
/* start with v1-2 */
sub_v3_v3v3(r_plane, verts[0]->co, verts[1]->co);
/* test the edge between v2-3, use if longer */
sub_v3_v3v3(vec, verts[1]->co, verts[2]->co);
if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec))
copy_v3_v3(r_plane, vec);
/* test the edge between v1-3, use if longer */
sub_v3_v3v3(vec, verts[2]->co, verts[0]->co);
if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
copy_v3_v3(r_plane, vec);
}
}
}
}
normalize_v3(r_plane);
}
int BM_select_history_check(BMesh *bm, void *data)
{
BMEditSelection *ese;
for (ese = bm->selected.first; ese; ese = ese->next) {
if (ese->data == data) {
return TRUE;
}
}
return FALSE;
}
void BM_select_history_remove(BMesh *bm, void *data)
{
BMEditSelection *ese;
for (ese = bm->selected.first; ese; ese = ese->next) {
if (ese->data == data) {
BLI_freelinkN(&(bm->selected), ese);
break;
}
}
}
void BM_select_history_clear(BMesh *bm)
{
BLI_freelistN(&bm->selected);
bm->selected.first = bm->selected.last = NULL;
}
void BM_select_history_store(BMesh *bm, void *data)
{
BMEditSelection *ese;
if (!BM_select_history_check(bm, data)) {
ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
ese->htype = ((BMHeader *)data)->htype;
ese->data = data;
BLI_addtail(&(bm->selected), ese);
}
}
void BM_select_history_validate(BMesh *bm)
{
BMEditSelection *ese, *nextese;
ese = bm->selected.first;
while (ese) {
nextese = ese->next;
if (!BM_elem_flag_test(ese->data, BM_ELEM_SELECT)) {
BLI_freelinkN(&(bm->selected), ese);
}
ese = nextese;
}
}
void BM_mesh_elem_flag_disable_all(BMesh *bm, const char htype, const char hflag)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
BM_FACES_OF_MESH};
BMIter iter;
BMHeader *ele;
int i;
if (hflag & BM_ELEM_SELECT) {
BM_select_history_clear(bm);
}
for (i = 0; i < 3; i++) {
if (htype & iter_types[i]) {
ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
for ( ; ele; ele = BM_iter_step(&iter)) {
if (hflag & BM_ELEM_SELECT) {
BM_elem_select_set(bm, ele, FALSE);
}
BM_elem_flag_disable(ele, hflag);
}
}
}
}
void BM_mesh_elem_flag_enable_all(BMesh *bm, const char htype, const char hflag)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
BM_FACES_OF_MESH};
BMIter iter;
BMHeader *ele;
int i;
if (hflag & BM_ELEM_SELECT) {
BM_select_history_clear(bm);
}
for (i = 0; i < 3; i++) {
if (htype & iter_types[i]) {
ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
for ( ; ele; ele = BM_iter_step(&iter)) {
if (hflag & BM_ELEM_SELECT) {
BM_elem_select_set(bm, ele, TRUE);
}
BM_elem_flag_enable(ele, hflag);
}
}
}
}
/***************** Mesh Hiding stuff *********** */
#define BM_ELEM_HIDE_SET(ele, hide) \
(hide) ? BM_elem_flag_enable(ele, BM_ELEM_HIDDEN) : BM_elem_flag_disable(ele, BM_ELEM_HIDDEN);
static void vert_flush_hide_set(BMesh *bm, BMVert *v)
{
BMIter iter;
BMEdge *e;
int hide = TRUE;
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
}
BM_ELEM_HIDE_SET(v, hide);
}
static void edge_flush_hide(BMesh *bm, BMEdge *e)
{
BMIter iter;
BMFace *f;
int hide = TRUE;
BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
}
BM_ELEM_HIDE_SET(e, hide);
}
void BM_vert_hide_set(BMesh *bm, BMVert *v, int hide)
{
/* vert hiding: vert + surrounding edges and faces */
BMIter iter, fiter;
BMEdge *e;
BMFace *f;
BM_ELEM_HIDE_SET(v, hide);
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
BM_ELEM_HIDE_SET(e, hide);
BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
BM_ELEM_HIDE_SET(f, hide);
}
}
}
void BM_edge_hide_set(BMesh *bm, BMEdge *e, int hide)
{
BMIter iter;
BMFace *f;
/* BMVert *v; */
/* edge hiding: faces around the edge */
BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
BM_ELEM_HIDE_SET(f, hide);
}
BM_ELEM_HIDE_SET(e, hide);
/* hide vertices if necassary */
vert_flush_hide_set(bm, e->v1);
vert_flush_hide_set(bm, e->v2);
}
void BM_face_hide_set(BMesh *bm, BMFace *f, int hide)
{
BMIter iter;
BMLoop *l;
BM_ELEM_HIDE_SET(f, hide);
BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
edge_flush_hide(bm, l->e);
}
BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
vert_flush_hide_set(bm, l->v);
}
}
#undef BM_ELEM_HIDE_SET
void BM_elem_hide_set(BMesh *bm, void *element, int hide)
{
BMHeader *h = element;
/* Follow convention of always deselecting before
* hiding an element */
if (hide) {
BM_elem_select_set(bm, element, FALSE);
}
switch (h->htype) {
case BM_VERT:
BM_vert_hide_set(bm, element, hide);
break;
case BM_EDGE:
BM_edge_hide_set(bm, element, hide);
break;
case BM_FACE:
BM_face_hide_set(bm, element, hide);
break;
}
}

@ -0,0 +1,625 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Geoffrey Bantle.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_mesh.c
* \ingroup bmesh
*
* BM mesh level functions.
*/
#include "MEM_guardedalloc.h"
#include "DNA_listBase.h"
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_tessmesh.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
#include "ED_mesh.h"
#include "bmesh_private.h"
/* used as an extern, defined in bmesh.h */
int bm_mesh_allocsize_default[4] = {512, 512, 2048, 512};
/* bmesh_error stub */
void bmesh_error(void)
{
printf("BM modelling error!\n");
/* This placeholder assert makes modelling errors easier to catch
* in the debugger, until bmesh_error is replaced with something
* better. */
BLI_assert(0);
}
static void bmesh_mempool_init(BMesh *bm, const int allocsize[4])
{
bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize[0], allocsize[0], FALSE, TRUE);
bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize[1], allocsize[1], FALSE, TRUE);
bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize[2], allocsize[2], FALSE, FALSE);
bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize[3], allocsize[3], FALSE, TRUE);
#ifdef USE_BMESH_HOLES
bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), allocsize[3], allocsize[3], FALSE, FALSE);
#endif
/* allocate one flag pool that we dont get rid of. */
bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512, FALSE, FALSE);
}
/*
* BMESH MAKE MESH
*
* Allocates a new BMesh structure.
* Returns -
* Pointer to a BM
*
*/
BMesh *BM_mesh_create(struct Object *ob, const int allocsize[4])
{
/* allocate the structure */
BMesh *bm = MEM_callocN(sizeof(BMesh), __func__);
bm->ob = ob;
/* allocate the memory pools for the mesh elements */
bmesh_mempool_init(bm, allocsize);
/* allocate one flag pool that we dont get rid of. */
bm->stackdepth = 1;
bm->totflags = 1;
return bm;
}
/*
* BMESH FREE MESH
*
* Frees a BMesh structure.
*/
void BM_mesh_data_free(BMesh *bm)
{
BMVert *v;
BMEdge *e;
BMLoop *l;
BMFace *f;
BMIter verts;
BMIter edges;
BMIter faces;
BMIter loops;
for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
CustomData_bmesh_free_block(&(bm->vdata), &(v->head.data));
}
for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
CustomData_bmesh_free_block(&(bm->edata), &(e->head.data));
}
for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
CustomData_bmesh_free_block(&(bm->pdata), &(f->head.data));
for (l = BM_iter_new(&loops, bm, BM_LOOPS_OF_FACE, f); l; l = BM_iter_step(&loops)) {
CustomData_bmesh_free_block(&(bm->ldata), &(l->head.data));
}
}
/* Free custom data pools, This should probably go in CustomData_free? */
if (bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
if (bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
if (bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
if (bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
/* free custom data */
CustomData_free(&bm->vdata, 0);
CustomData_free(&bm->edata, 0);
CustomData_free(&bm->ldata, 0);
CustomData_free(&bm->pdata, 0);
/* destroy element pools */
BLI_mempool_destroy(bm->vpool);
BLI_mempool_destroy(bm->epool);
BLI_mempool_destroy(bm->lpool);
BLI_mempool_destroy(bm->fpool);
/* destroy flag pool */
BLI_mempool_destroy(bm->toolflagpool);
#ifdef USE_BMESH_HOLES
BLI_mempool_destroy(bm->looplistpool);
#endif
/* These tables aren't used yet, so it's not stricly necessary
* to 'end' them (with 'e' param) but if someone tries to start
* using them, having these in place will save a lot of pain */
mesh_octree_table(NULL, NULL, NULL, 'e');
mesh_mirrtopo_table(NULL, 'e');
BLI_freelistN(&bm->selected);
BMO_error_clear(bm);
}
void BM_mesh_clear(BMesh *bm)
{
Object *ob = bm->ob;
/* free old mesh */
BM_mesh_data_free(bm);
memset(bm, 0, sizeof(BMesh));
/* re-initialize mesh */
bm->ob = ob;
/* allocate the memory pools for the mesh elements */
bmesh_mempool_init(bm, bm_mesh_allocsize_default);
bm->stackdepth = 1;
bm->totflags = 1;
}
/*
* BMESH FREE MESH
*
* Frees a BMesh structure.
*/
void BM_mesh_free(BMesh *bm)
{
BM_mesh_data_free(bm);
MEM_freeN(bm);
}
/*
* BMESH COMPUTE NORMALS
*
* Updates the normals of a mesh.
* Note that this can only be called
*
*/
void BM_mesh_normals_update(BMesh *bm)
{
BMVert *v;
BMFace *f;
BMLoop *l;
BMEdge *e;
BMIter verts;
BMIter faces;
BMIter loops;
BMIter edges;
unsigned int maxlength = 0;
int index;
float (*projectverts)[3];
float (*edgevec)[3];
/* first, find out the largest face in mesh */
BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
continue;
if (f->len > maxlength) maxlength = f->len;
}
/* make sure we actually have something to do */
if (maxlength < 3) return;
/* allocate projectverts array */
projectverts = MEM_callocN(sizeof(float) * maxlength * 3, "BM normal computation array");
/* calculate all face normals */
BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
continue;
#if 0 /* UNUSED */
if (f->head.flag & BM_NONORMCALC)
continue;
#endif
bmesh_update_face_normal(bm, f, f->no, projectverts);
}
/* Zero out vertex normals */
BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
continue;
zero_v3(v->no);
}
/* compute normalized direction vectors for each edge. directions will be
* used below for calculating the weights of the face normals on the vertex
* normals */
index = 0;
edgevec = MEM_callocN(sizeof(float) * 3 * bm->totedge, "BM normal computation array");
BM_ITER(e, &edges, bm, BM_EDGES_OF_MESH, NULL) {
BM_elem_index_set(e, index); /* set_inline */
if (e->l) {
sub_v3_v3v3(edgevec[index], e->v2->co, e->v1->co);
normalize_v3(edgevec[index]);
}
else {
/* the edge vector will not be needed when the edge has no radial */
}
index++;
}
bm->elem_index_dirty &= ~BM_EDGE;
/* add weighted face normals to vertices */
BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
continue;
BM_ITER(l, &loops, bm, BM_LOOPS_OF_FACE, f) {
float *e1diff, *e2diff;
float dotprod;
float fac;
/* calculate the dot product of the two edges that
* meet at the loop's vertex */
e1diff = edgevec[BM_elem_index_get(l->prev->e)];
e2diff = edgevec[BM_elem_index_get(l->e)];
dotprod = dot_v3v3(e1diff, e2diff);
/* edge vectors are calculated from e->v1 to e->v2, so
* adjust the dot product if one but not both loops
* actually runs from from e->v2 to e->v1 */
if ((l->prev->e->v1 == l->prev->v) ^ (l->e->v1 == l->v)) {
dotprod = -dotprod;
}
fac = saacos(-dotprod);
/* accumulate weighted face normal into the vertex's normal */
madd_v3_v3fl(l->v->no, f->no, fac);
}
}
/* normalize the accumulated vertex normals */
BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
continue;
if (normalize_v3(v->no) == 0.0f) {
normalize_v3_v3(v->no, v->co);
}
}
MEM_freeN(edgevec);
MEM_freeN(projectverts);
}
/*
This function ensures correct normals for the mesh, but
sets the flag BM_ELEM_TAG in flipped faces, to allow restoration
of original normals.
if undo is 0: calculate right normals
if undo is 1: restore original normals
*/
//keep in sycn with utils.c!
#define FACE_FLIP 8
static void bmesh_rationalize_normals(BMesh *bm, int undo)
{
BMOperator bmop;
BMFace *f;
BMIter iter;
if (undo) {
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
BM_face_normal_flip(bm, f);
}
BM_elem_flag_disable(f, BM_ELEM_TAG);
}
return;
}
BMO_op_initf(bm, &bmop, "righthandfaces faces=%af doflip=%d", FALSE);
BMO_push(bm, &bmop);
bmesh_righthandfaces_exec(bm, &bmop);
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (BMO_elem_flag_test(bm, f, FACE_FLIP))
BM_elem_flag_enable(f, BM_ELEM_TAG);
else BM_elem_flag_disable(f, BM_ELEM_TAG);
}
BMO_pop(bm);
BMO_op_finish(bm, &bmop);
}
static void bmesh_set_mdisps_space(BMesh *bm, int from, int to)
{
/* switch multires data out of tangent space */
if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
Object *ob = bm->ob;
BMEditMesh *em = BMEdit_Create(bm, FALSE);
DerivedMesh *dm = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE);
MDisps *mdisps;
BMFace *f;
BMIter iter;
// int i = 0; // UNUSED
multires_set_space(dm, ob, from, to);
mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
BMLoop *l;
BMIter liter;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
MDisps *lmd = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
if (!lmd->disps) {
printf("%s: warning - 'lmd->disps' == NULL\n", __func__);
}
if (lmd->disps && lmd->totdisp == mdisps->totdisp) {
memcpy(lmd->disps, mdisps->disps, sizeof(float) * 3 * lmd->totdisp);
}
else if (mdisps->disps) {
if (lmd->disps)
MEM_freeN(lmd->disps);
lmd->disps = MEM_dupallocN(mdisps->disps);
lmd->totdisp = mdisps->totdisp;
}
mdisps++;
// i += 1;
}
}
dm->needsFree = 1;
dm->release(dm);
/* setting this to NULL prevents BMEdit_Free from freeing it */
em->bm = NULL;
BMEdit_Free(em);
MEM_freeN(em);
}
}
/*
* BMESH BEGIN/END EDIT
*
* Functions for setting up a mesh for editing and cleaning up after
* the editing operations are done. These are called by the tools/operator
* API for each time a tool is executed.
*/
void bmesh_begin_edit(BMesh *bm, int flag)
{
bm->opflag = flag;
/* Most operators seem to be using BMO_OP_FLAG_UNTAN_MULTIRES to change the MDisps to
* absolute space during mesh edits. With this enabled, changes to the topology
* (loop cuts, edge subdivides, etc) are not reflected in the higher levels of
* the mesh at all, which doesn't seem right. Turning off completely for now,
* until this is shown to be better for certain types of mesh edits. */
#if BMOP_UNTAN_MULTIRES_ENABLED
/* switch multires data out of tangent space */
if ((flag & BMO_OP_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
bmesh_set_mdisps_space(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
/* ensure correct normals, if possible */
bmesh_rationalize_normals(bm, 0);
BM_mesh_normals_update(bm);
}
else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
bmesh_rationalize_normals(bm, 0);
}
#else
if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
bmesh_rationalize_normals(bm, 0);
}
#endif
}
void bmesh_end_edit(BMesh *bm, int flag)
{
/* BMO_OP_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_begin_edit. */
#if BMOP_UNTAN_MULTIRES_ENABLED
/* switch multires data into tangent space */
if ((flag & BMO_OP_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
/* set normals to their previous winding */
bmesh_rationalize_normals(bm, 1);
bmesh_set_mdisps_space(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
}
else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
bmesh_rationalize_normals(bm, 1);
}
#else
if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
bmesh_rationalize_normals(bm, 1);
}
#endif
bm->opflag = 0;
/* compute normals, clear temp flags and flush selections */
BM_mesh_normals_update(bm);
BM_mesh_select_mode_flush(bm);
}
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
{
BMIter iter;
BMHeader *ele;
#ifdef DEBUG
BM_ELEM_INDEX_VALIDATE(bm, "Should Never Fail!", __func__);
#endif
if (hflag & BM_VERT) {
if (bm->elem_index_dirty & BM_VERT) {
int index = 0;
BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
BM_elem_index_set(ele, index); /* set_ok */
index++;
}
bm->elem_index_dirty &= ~BM_VERT;
BLI_assert(index == bm->totvert);
}
else {
// printf("%s: skipping vert index calc!\n", __func__);
}
}
if (hflag & BM_EDGE) {
if (bm->elem_index_dirty & BM_EDGE) {
int index = 0;
BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
BM_elem_index_set(ele, index); /* set_ok */
index++;
}
bm->elem_index_dirty &= ~BM_EDGE;
BLI_assert(index == bm->totedge);
}
else {
// printf("%s: skipping edge index calc!\n", __func__);
}
}
if (hflag & BM_FACE) {
if (bm->elem_index_dirty & BM_FACE) {
int index = 0;
BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
BM_elem_index_set(ele, index); /* set_ok */
index++;
}
bm->elem_index_dirty &= ~BM_FACE;
BLI_assert(index == bm->totface);
}
else {
// printf("%s: skipping face index calc!\n", __func__);
}
}
}
/* array checking/setting macros */
/* currently vert/edge/loop/face index data is being abused, but we should
* eventually be able to rely on it being valid. To this end, there are macros
* that validate them (so blender doesnt crash), but also print errors so we can
* fix the offending parts of the code, this way after some months we can
* confine this code for debug mode.
*
*
*/
void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
const char *msg_a, const char *msg_b)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
BM_FACES_OF_MESH};
const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
const char *type_names[3] = {"vert", "edge", "face"};
BMIter iter;
BMHeader *ele;
int i;
int is_any_error = 0;
for (i = 0; i < 3; i++) {
const int is_dirty = (flag_types[i] & bm->elem_index_dirty);
int index = 0;
int is_error = FALSE;
int err_val = 0;
int err_idx = 0;
BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
if (!is_dirty) {
if (BM_elem_index_get(ele) != index) {
err_val = BM_elem_index_get(ele);
err_idx = index;
is_error = TRUE;
}
}
BM_elem_index_set(ele, index); /* set_ok */
index++;
}
if ((is_error == TRUE) && (is_dirty == FALSE)) {
is_any_error = TRUE;
fprintf(stderr,
"Invalid Index: at %s, %s, %s[%d] invalid index %d, '%s', '%s'\n",
location, func, type_names[i], err_idx, err_val, msg_a, msg_b);
}
else if ((is_error == FALSE) && (is_dirty == TRUE)) {
#if 0 /* mostly annoying */
/* dirty may have been incorrectly set */
fprintf(stderr,
"Invalid Dirty: at %s, %s (%s), dirty flag was set but all index values are correct, '%s', '%s'\n",
location, func, type_names[i], msg_a, msg_b);
#endif
}
}
#if 0 /* mostly annoying, even in debug mode */
#ifdef DEBUG
if (is_any_error == 0) {
fprintf(stderr,
"Valid Index Success: at %s, %s, '%s', '%s'\n",
location, func, msg_a, msg_b);
}
#endif
#endif
(void) is_any_error; /* shut up the compiler */
}
BMVert *BM_vert_at_index(BMesh *bm, const int index)
{
return BLI_mempool_findelem(bm->vpool, index);
}
BMEdge *BM_edge_at_index(BMesh *bm, const int index)
{
return BLI_mempool_findelem(bm->epool, index);
}
BMFace *BM_face_at_index(BMesh *bm, const int index)
{
return BLI_mempool_findelem(bm->fpool, index);
}

@ -0,0 +1,769 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_mods.c
* \ingroup bmesh
*
* This file contains functions for locally modifying
* the topology of existing mesh data. (split, join, flip etc).
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_array.h"
#include "BLI_smallhash.h"
#include "BKE_customdata.h"
#include "bmesh.h"
#include "bmesh_private.h"
/**
* bmesh_dissolve_disk
*
* Turns the face region surrounding a manifold vertex into
* A single polygon.
*
*
* Example:
*
* |=========| |=========|
* | \ / | | |
* Before: | V | After: | |
* | / \ | | |
* |=========| |=========|
*
*
*/
#if 1
int BM_vert_dissolve(BMesh *bm, BMVert *v)
{
BMIter iter;
BMEdge *e;
int len = 0;
if (!v) {
return FALSE;
}
e = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, v);
for ( ; e; e = BM_iter_step(&iter)) {
len++;
}
if (len == 1) {
if (v->e)
BM_edge_kill(bm, v->e);
BM_vert_kill(bm, v);
return TRUE;
}
if (!BM_vert_is_manifold(bm, v)) {
if (!v->e) BM_vert_kill(bm, v);
else if (!v->e->l) {
BM_edge_kill(bm, v->e);
BM_vert_kill(bm, v);
}
else {
return FALSE;
}
return TRUE;
}
return BM_disk_dissolve(bm, v);
}
int BM_disk_dissolve(BMesh *bm, BMVert *v)
{
BMFace *f, *f2;
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
int len = 0;
if (!BM_vert_is_manifold(bm, v)) {
return FALSE;
}
if (v->e) {
/* v->e we keep, what else */
e = v->e;
do {
e = bmesh_disk_nextedge(e, v);
if (!(BM_edge_share_faces(e, v->e))) {
keepedge = e;
baseedge = v->e;
break;
}
len++;
} while (e != v->e);
}
/* this code for handling 2 and 3-valence verts
* may be totally bad */
if (keepedge == NULL && len == 3) {
/* handle specific case for three-valence. solve it by
* increasing valence to four. this may be hackish. . */
BMLoop *loop = e->l;
if (loop->v == v) loop = loop->next;
if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL))
return FALSE;
if (!BM_disk_dissolve(bm, v)) {
return FALSE;
}
return TRUE;
}
else if (keepedge == NULL && len == 2) {
/* collapse the verte */
e = BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE);
if (!e) {
return FALSE;
}
/* handle two-valenc */
f = e->l->f;
f2 = e->l->radial_next->f;
if (f != f2 && !BM_faces_join_pair(bm, f, f2, e)) {
return FALSE;
}
return TRUE;
}
if (keepedge) {
int done = 0;
while (!done) {
done = 1;
e = v->e;
do {
f = NULL;
len = bmesh_radial_length(e->l);
if (len == 2 && (e != baseedge) && (e != keepedge)) {
f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
/* return if couldn't join faces in manifold
* conditions */
//!disabled for testing why bad things happen
if (!f) {
return FALSE;
}
}
if (f) {
done = 0;
break;
}
e = bmesh_disk_nextedge(e, v);
} while (e != v->e);
}
/* collapse the verte */
e = BM_vert_collapse_faces(bm, baseedge, v, 1.0, TRUE);
if (!e) {
return FALSE;
}
/* get remaining two face */
f = e->l->f;
f2 = e->l->radial_next->f;
if (f != f2) {
/* join two remaining face */
if (!BM_faces_join_pair(bm, f, f2, e)) {
return FALSE;
}
}
}
return TRUE;
}
#else
void BM_disk_dissolve(BMesh *bm, BMVert *v)
{
BMFace *f;
BMEdge *e;
BMIter iter;
int done, len;
if (v->e) {
done = 0;
while (!done) {
done = 1;
/* loop the edges looking for an edge to dissolv */
for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, v); e;
e = BM_iter_step(&iter)) {
f = NULL;
len = bmesh_cycle_length(&(e->l->radial));
if (len == 2) {
f = BM_faces_join_pair(bm, e->l->f, ((BMLoop *)(e->l->radial_next))->f, e);
}
if (f) {
done = 0;
break;
}
};
}
BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE);
}
}
#endif
/**
* BM_faces_join_pair
*
* Joins two adjacenct faces togather.
*
* Because this method calls to BM_faces_join to do its work, ff a pair
* of faces share multiple edges, the pair of faces will be joined at
* every edge (not just edge e). This part of the functionality might need
* to be reconsidered.
*
* If the windings do not match the winding of the new face will follow
* f1's winding (i.e. f2 will be reversed before the join).
*
* Returns:
* pointer to the combined face
*/
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l1, *l2;
BMEdge *jed = NULL;
BMFace *faces[2] = {f1, f2};
jed = e;
if (!jed) {
BMLoop *l_first;
/* search for an edge that has both these faces in its radial cycl */
l1 = l_first = BM_FACE_FIRST_LOOP(f1);
do {
if (l1->radial_next->f == f2) {
jed = l1->e;
break;
}
} while ((l1 = l1->next) != l_first);
}
if (!jed) {
bmesh_error();
return NULL;
}
l1 = jed->l;
if (!l1) {
bmesh_error();
return NULL;
}
l2 = l1->radial_next;
if (l1->v == l2->v) {
bmesh_loop_reverse(bm, f2);
}
f1 = BM_faces_join(bm, faces, 2);
return f1;
}
/* connects two verts together, automatically (if very naively) finding the
* face they both share (if there is one) and splittling it. use this at your
* own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
* multiple faces, etc).
*
* this is really only meant for cases where you don't know before hand the face
* the two verts belong to for splitting (e.g. the subdivision operator).
*/
BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf)
{
BMIter iter, iter2;
BMVert *v;
BMLoop *nl;
BMFace *face;
/* be warned: this can do weird things in some ngon situation, see BM_LegalSplit */
for (face = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); face; face = BM_iter_step(&iter)) {
for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, face); v; v = BM_iter_step(&iter2)) {
if (v == v2) {
face = BM_face_split(bm, face, v1, v2, &nl, NULL);
if (nf) *nf = face;
return nl->e;
}
}
}
return NULL;
}
/**
* BM_face_split
*
* Splits a single face into two.
*
* f - the original face
* v1 & v2 - vertices which define the split edge, must be different
* nl - pointer which will receive the BMLoop for the split edge in the new face
*
* Notes: the
* Returns -
* Pointer to the newly created face representing one side of the split
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*
*/
BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *UNUSED(example))
{
const int has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
BMFace *nf, *of;
/* do we have a multires layer */
if (has_mdisp) {
of = BM_face_copy(bm, f, 0, 0);
}
#ifdef USE_BMESH_HOLES
nf = bmesh_sfme(bm, f, v1, v2, nl, NULL);
#else
nf = bmesh_sfme(bm, f, v1, v2, nl);
#endif
if (nf) {
BM_elem_attrs_copy(bm, bm, f, nf);
copy_v3_v3(nf->no, f->no);
/* handle multires update */
if (has_mdisp && (nf != f)) {
BMLoop *l_iter;
BMLoop *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
} while ((l_iter = l_iter->next) != l_first);
l_iter = l_first = BM_FACE_FIRST_LOOP(nf);
do {
BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
} while ((l_iter = l_iter->next) != l_first);
BM_face_kill(bm, of);
BM_face_multires_bounds_smooth(bm, f);
BM_face_multires_bounds_smooth(bm, nf);
}
}
return nf;
}
/**
* BM_vert_collapse_faces
*
* Collapses a vertex that has only two manifold edges
* onto a vertex it shares an edge with. Fac defines
* the amount of interpolation for Custom Data.
*
* Note that this is not a general edge collapse function.
*
* Note this function is very close to 'BM_vert_collapse_edges', both collapse
* a vertex and return a new edge. Except this takes a factor and merges
* custom data.
*
* BMESH_TODO:
* Insert error checking for KV valance.
*
* @param fac The factor along the edge
* @param join_faces When true the faces around the vertex will be joined
* otherwise collapse the vertex by merging the 2 edges this vert touches into one.
* @returns The New Edge
*/
BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, const int join_faces)
{
BMEdge *ne = NULL;
BMVert *tv = bmesh_edge_getothervert(ke, kv);
BMEdge *e2;
BMVert *tv2;
BMIter iter;
BMLoop *l_iter = NULL, *kvloop = NULL, *tvloop = NULL;
void *src[2];
float w[2];
/* Only intended to be called for 2-valence vertices */
BLI_assert(bmesh_disk_count(kv) <= 2);
/* first modify the face loop data */
w[0] = 1.0f - fac;
w[1] = fac;
if (ke->l) {
l_iter = ke->l;
do {
if (l_iter->v == tv && l_iter->next->v == kv) {
tvloop = l_iter;
kvloop = l_iter->next;
src[0] = kvloop->head.data;
src[1] = tvloop->head.data;
CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
}
} while ((l_iter = l_iter->radial_next) != ke->l);
}
/* now interpolate the vertex data */
BM_data_interp_from_verts(bm, kv, tv, kv, fac);
e2 = bmesh_disk_nextedge(ke, kv);
tv2 = BM_edge_other_vert(e2, kv);
if (join_faces) {
BMFace **faces = NULL, *f;
BLI_array_staticdeclare(faces, 8);
BM_ITER(f, &iter, bm, BM_FACES_OF_VERT, kv) {
BLI_array_append(faces, f);
}
if (BLI_array_count(faces) >= 2) {
BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces));
if (f2) {
BMLoop *nl = NULL;
if (BM_face_split(bm, f2, tv, tv2, &nl, NULL)) {
ne = nl->e;
}
}
}
BLI_array_free(faces);
return ne;
}
/* single face or no faces */
/* same as BM_vert_collapse_edges() however we already
* have vars to perform this operation so dont call. */
bmesh_jekv(bm, ke, kv);
ne = BM_edge_exists(tv, tv2);
return ne;
}
/**
* BM_vert_collapse_edges
*
* Collapses a vertex onto another vertex it shares an edge with.
*
* Returns -
* The New Edge
*/
BMEdge *BM_vert_collapse_edges(BMesh *bm, BMEdge *ke, BMVert *kv)
{
/* nice example implimentation but we want loops to have their customdata
* accounted for */
#if 0
BMEdge *ne = NULL;
/* Collapse between 2 edges */
/* in this case we want to keep all faces and not join them,
* rather just get rid of the veretex - see bug [#28645] */
BMVert *tv = bmesh_edge_getothervert(ke, kv);
if (tv) {
BMEdge *e2 = bmesh_disk_nextedge(ke, kv);
if (e2) {
BMVert *tv2 = BM_edge_other_vert(e2, kv);
if (tv2) {
/* only action, other calls here only get the edge to return */
bmesh_jekv(bm, ke, kv);
ne = BM_edge_exists(tv, tv2);
}
}
}
return ne;
#else
/* with these args faces are never joined, same as above
* but account for loop customdata */
return BM_vert_collapse_faces(bm, ke, kv, 1.0f, FALSE);
#endif
}
#undef DO_V_INTERP
/**
* BM_split_edge
*
* Splits an edge. v should be one of the vertices in e and
* defines the direction of the splitting operation for interpolation
* purposes.
*
* Returns -
* the new vert
*/
BMVert *BM_edge_split(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent)
{
BMVert *nv, *v2;
BMFace **oldfaces = NULL;
BMEdge *dummy;
BLI_array_staticdeclare(oldfaces, 32);
SmallHash hash;
/* we need this for handling multire */
if (!ne)
ne = &dummy;
/* do we have a multires layer */
if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l) {
BMLoop *l;
int i;
l = e->l;
do {
BLI_array_append(oldfaces, l->f);
l = l->radial_next;
} while (l != e->l);
/* create a hash so we can differentiate oldfaces from new face */
BLI_smallhash_init(&hash);
for (i = 0; i < BLI_array_count(oldfaces); i++) {
oldfaces[i] = BM_face_copy(bm, oldfaces[i], 1, 1);
BLI_smallhash_insert(&hash, (intptr_t)oldfaces[i], NULL);
}
}
v2 = bmesh_edge_getothervert(e, v);
nv = bmesh_semv(bm, v, e, ne);
if (nv == NULL) {
return NULL;
}
sub_v3_v3v3(nv->co, v2->co, v->co);
madd_v3_v3v3fl(nv->co, v->co, nv->co, percent);
if (ne) {
(*ne)->head.hflag = e->head.hflag;
BM_elem_attrs_copy(bm, bm, e, *ne);
}
/* v->nv->v2 */
BM_data_interp_face_vert_edge(bm, v2, v, nv, e, percent);
BM_data_interp_from_verts(bm, v, v2, nv, percent);
if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l && nv) {
int i, j;
/* interpolate new/changed loop data from copied old face */
for (j = 0; j < 2; j++) {
for (i = 0; i < BLI_array_count(oldfaces); i++) {
BMEdge *e1 = j ? *ne : e;
BMLoop *l, *l2;
l = e1->l;
if (!l) {
bmesh_error();
break;
}
do {
if (!BLI_smallhash_haskey(&hash, (intptr_t)l->f)) {
BMLoop *l2_first;
l2 = l2_first = BM_FACE_FIRST_LOOP(l->f);
do {
BM_loop_interp_multires(bm, l2, oldfaces[i]);
} while ((l2 = l2->next) != l2_first);
}
l = l->radial_next;
} while (l != e1->l);
}
}
/* destroy the old face */
for (i = 0; i < BLI_array_count(oldfaces); i++) {
BM_face_verts_kill(bm, oldfaces[i]);
}
/* fix boundaries a bit, doesn't work too well quite ye */
#if 0
for (j = 0; j < 2; j++) {
BMEdge *e1 = j ? *ne : e;
BMLoop *l, *l2;
l = e1->l;
if (!l) {
bmesh_error();
break;
}
do {
BM_face_multires_bounds_smooth(bm, l->f);
l = l->radial_next;
} while (l != e1->l);
}
#endif
BLI_array_free(oldfaces);
BLI_smallhash_release(&hash);
}
return nv;
}
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts)
{
int i;
float percent;
BMVert *nv = NULL;
for (i = 0; i < numcuts; i++) {
percent = 1.0f / (float)(numcuts + 1 - i);
nv = BM_edge_split(bm, e->v2, e, NULL, percent);
}
return nv;
}
int BM_face_validate(BMesh *bm, BMFace *face, FILE *err)
{
BMIter iter;
BLI_array_declare(verts);
BMVert **verts = NULL;
BMLoop *l;
int ret = 1, i, j;
if (face->len == 2) {
fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
fflush(err);
}
for (l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, face); l; l = BM_iter_step(&iter)) {
BLI_array_growone(verts);
verts[BLI_array_count(verts) - 1] = l->v;
if (l->e->v1 == l->e->v2) {
fprintf(err, "Found bmesh edge with identical verts!\n");
fprintf(err, " edge ptr: %p, vert: %p\n", l->e, l->e->v1);
fflush(err);
ret = 0;
}
}
for (i = 0; i < BLI_array_count(verts); i++) {
for (j = 0; j < BLI_array_count(verts); j++) {
if (j == i) {
continue;
}
if (verts[i] == verts[j]) {
fprintf(err, "Found duplicate verts in bmesh face!\n");
fprintf(err, " face ptr: %p, vert: %p\n", face, verts[i]);
fflush(err);
ret = 0;
}
}
}
BLI_array_free(verts);
return ret;
}
/*
* BM Rotate Edge
*
* Spins an edge topologically, either counter-clockwise or clockwise.
* If ccw is true, the edge is spun counter-clockwise, otherwise it is
* spun clockwise.
*
* Returns the spun edge. Note that this works by dissolving the edge
* then re-creating it, so the returned edge won't have the same pointer
* address as the original one.
*
* Returns NULL on error (e.g., if the edge isn't surrounded by exactly
* two faces).
*/
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, int ccw)
{
BMVert *v1, *v2;
BMLoop *l, *l1, *l2, *nl;
BMFace *f;
BMIter liter;
v1 = e->v1;
v2 = e->v2;
if (BM_edge_face_count(e) != 2)
return NULL;
/* If either of e's vertices has valence 2, then
* dissolving the edge would leave a spur, so not allowed */
if (BM_vert_edge_count(e->v1) == 2 || BM_vert_edge_count(e->v2) == 2)
return NULL;
f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
if (f == NULL)
return NULL;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
if (l->v == v1)
l1 = l;
else if (l->v == v2)
l2 = l;
}
if (ccw) {
l1 = l1->prev;
l2 = l2->prev;
}
else {
l1 = l1->next;
l2 = l2->next;
}
if (!BM_face_split(bm, f, l1->v, l2->v, &nl, NULL))
return NULL;
return nl->e;
}
BMVert *BM_vert_rip ( BMesh *bm, BMFace *sf, BMVert *sv)
{
return bmesh_urmv(bm, sf, sv);
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More