Class MNFace

3DS Max Plug-In SDK

Class MNFace

See Also: Class FlagUser, Class MNFace, Class BitArray.

class MNFace : public FlagUser

Description:

This class is available in release 2.0 and later only.

MNFace is the face structure used with the MNMesh mesh. MNFaces need not be triangles. They also may contain "hidden" vertices which are used in converting the face back to triangles. This "triangulation" is always maintained in the face.

All methods of this class are implemented by the system.

Friend Classes:

friend class MNMesh;

Data Members:

private:

int dalloc

This is the amount of space allocated for verts, edges, mapping coords, and other information that's based on degree (deg).

int talloc

This is the amount of space allocated for the triangulation.

public:

int deg

Degree: this is the number of vertices and edges that this face has.

int *vtx

This is the list of vertices that make up the corners of this face. Each value is an index into the parent MNMesh's list of MNVerts.

int *edg

This is the list of edges that border this face, in order. Each edg[i] goes between vtx[i] and vtx[(i+1)%deg]. Each value is an index into the parent MNMesh’s list of MNEdges. These values may not be valid if the MNMesh’s MN_MESH_FILLED_IN flag is not set.

int *diag

This is where the triangulation is stored. The number of triangles in a face is given by deg - 2 + hdeg*2. This array contains three times this number, for all the corners of all the sub-triangles. The triangle values are indices into the vtx and hvtx arrays of this face. Hidden vertices are indicated by values less than zero: hvtx[i] is represented by -1-i. Thus a triangle (1, 2, -2) would represent a triangle using vtx[1], vtx[2], and hvtx[-1]. The diag array's allocated size is always (dalloc-3)*2. If dalloc==3 (triangle), this pointer is NULL.

DWORD smGroup

This contains the smoothing groups assigned to this face.

MtlID material

This is the material ID assigned to this face.

int track

This member is obsolete and should not be used.

BitArray visedg

Contains a visibility bit for each edge on this face. See the MNMesh note on edge selection & visibility for more information.

BitArray edgsel

Contains a selection bit for each edge on this face. See the MNMesh note on edge selection & visibility for more information.

Flags:

MN_SEL

Indicates that the face is selected.

MN_TARG

Indicates that the face is targeted. (See the MNMesh methods starting with the words TargetBy.)

MN_DEAD

Indicates that the face is not used and should be ignored. Faces with the MN_DEAD flag are deleted in the next MNMesh call to CollapseDeadFaces ().

MN_FACE_OPEN_REGION

This flag is available in release 2.5 and later only.

This face is part of a region of the mesh that is not closed, i.e. there are 1-sided edges. This means that the mesh is not a solid object, it has gaps or holes. The flag is set by the

MN_FACE_CHECKED

This flag is available in release 2.5 and later only.

Reserved for internal use (in recursive face-traversing algorithms).

MN_FACE_CHANGED

This flag can be cleared on all faces before an operation that moves some of the vertices of an MNMesh, then set for each face touching one of the moved vertices. This tells the parent MNMesh that these faces may need to have information such as triangulation recomputed. This flag is set by the MNMesh method SabinDoo in particular.

MN_FACE_CULLED

Indicates that the face is culled (used during hit-testing). Release 4.2 and above

MN_FACE_WHATEVER

Developers should not use this flag and should restrict themselves to MN_USER and higher bits.

MN_USER(1<<16)

Flag bits at or above MN_USER are reserved in all MNMesh components for the plug-in developer, if needed. Since FlagUser-derived classes have 32 flag bits, this allows for up to 16 user-defined flags.

Methods:

Prototype:

MNFace();

Remarks:

Constructor. Initializes the face’s arrays to NULL.

Prototype:

MNFace(int d);

Remarks:

Constructor. Initializes the face’s degree to d and allocates space for all the arrays.

Prototype:

MNFace(const MNFace *from);

Remarks:

Constructor. Copies flags, smoothing groups, and material from "from", but initializes the face’s arrays to NULL and degree to 0.

Prototype:

~MNFace();

Remarks:

Frees all arrays.

Prototype:

void Init();

Remarks:

This method is available in release 4.0 and later only.

Initialize the face.

Prototype:

void SetDeg (int d);

Remarks:

This method is available in release 4.0 and later only.

Set the number of edges and vertices this face has.

Parameters:

int d

Number of vertices and edges.

Prototype:

void Clear();

Remarks:

Frees all arrays, setting them to NULL, and resets degree.

Prototype:

int TriNum();

Remarks:

This method is available in release 3.0 and later only.

Returns the number of triangles in this face.

Prototype:

int FindTriPoint (int edge);

Remarks:

This method is available in release 4.0 and later only.

Given the index of a particular edge, this routine returns the point (distinct from edge and (edge+1)%deg) that forms a triangle with the edge, given the current scheme of diagonals.

Parameters:

int edge

An index into the vertex array (in the range 0 to deg-1) that indicates the starting vertex of the edge. (In other words, the edge falls between vertex vtx[edge] and vtx[(edge+1)%deg].)

Return Value:

The index of the desired vertex, again in the (0,deg-1) range, or edge if there's an error.

Prototype:

int FindTriPoint (int a, int b);

Remarks:

This method is available in release 4.0 and later only.

Given two verts that form a diagonal in the polygon, this method finds the vertex between them that connects by a diagonal or an outer edge to both of them. (Here, "between them" means after a and before b in sequence around the outside of the polygon. If we have an octagon where a=6 and b=2, the result would be 7, 0, or 1. To get the other result, in the 3,4,5 range, call the method with a=2 and b=6.)

Parameters:

int a, b

Two vertices, "internally indexed" in the 0 to deg-1 range. This method is only guaranteed to work if the vertices share a diagonal. (Otherwise, there may be no solution.)

Return Value:

The index of the desired vertex, again in the (0,deg-1) range, or a if there's an error.

Prototype:

void GetTriangles (Tab<int> &tri);

Remarks:

This method is available in release 4.0 and later only.

This method fills in the table with the full triangulation for the face, based on the internal diagonal list. The table is set to size (deg-2)*3.

Parameters:

Tab<int> &tri

The table of triangles.

Prototype:

void DiagSort (int dnum, int *diag);

Remarks:

This method is available in release 4.0 and later only.

Note that this function is not part of the class but is available for us.

This sorts the diagonals in the following fashion: each diagonal is reordered so that its smaller index comes first, then its larger. Then the list of diagonals is sorted so that it increases by second index, then decreases by first index. Such an ordered list for a 9-gon might be (1,3),(0,3), (0,4),(5,7),(4,7),(4,8). (This order is especially convenient for converting into triangles - it makes for a linear-time conversion.) DiagSort() uses qsort for speed.

Parameters:

int dnum

The size of the diag array - essentially double the number of diagonals.

int *diag

The diagonals.

Prototype:

void SetAlloc(int d, int h=0);

Remarks:

Allocates enough memory in the arrays for the face to have degree d, but does not actually set the degree. If the arrays are already large enough (or larger), it does not reallocate them. You generally don’t need to use this method separately; MakePoly, Insert, and other methods which may require additional memory will call this if needed.

Prototype:

void MakePoly(int fdeg, int *vv, bool *vis=NULL, bool *sel=NULL);

Remarks:

This method is available in release 3.0 and later only.

Makes this face into a polygon with the specified vertices and other information. This routine also supplies a default triangulation for the face; however, since this MNFace-level routine cannot access the vertex positions contained in the parent MNMesh, this triangulation may not work for non-convex faces. If the face may not be convex, a call to MNMesh::RetriangulateFace for this face will correct the triangulation.

Parameters:

int fdeg

The degree to set this face to.

int *vv

The list of vertices for this face. There must be at least fdeg of these. These values should be indices into the parent MNMesh’s array of MNVerts.

bool *vis=NULL

The edge visibility flags for the edges of this face. If this is NULL, it is ignored; otherwise, there must be at least fdeg of these. vis[i] represents the visibility of the edge going from vv[i] to vv[(i+1)%fdeg]. See the MNMesh note on edge selection & visibility for more information.

bool *sel=NULL

The edge selection flags for the edges of this face. If this is NULL, it is ignored; otherwise, there must be at least fdeg of these. sel[i] represents the selection bit of the edge going from vv[i] to vv[(i+1)%fdeg]. See the MNMesh note on edge selection & visibility for more information.

Prototype:

void Insert(int pos, int num=1);

Remarks:

Inserts space for more vertices and edges on this face. This is used, for example, when two faces are joined, to add room for the vertices & edges of one face to the other. This routine also renumbers the existing vertices and corrects the existing face triangulation, although it cannot provide the triangulation for the new vertices. It reserves space for the new triangles at the end of the triangle array. If you do not want to compute the triangulation for the new vertices yourself, you may use the MNMesh RetriangulateFace method after filling in the new vertices.

Parameters:

int pos

The location within the face where the new vertices and edges should be added.

int num

The number of new vertices and edges.

Prototype:

void Delete(int pos, int num=1, int edir=1, bool fixtri=TRUE);

Remarks:

Deletes vertices & edges from this face. This routine also corrects the face triangulation, removing those triangles that include the deleted edges and re-indexing the rest. However, delete may cause the triangulation to become invalid, by causing one or more of the corrected triangles to have a flipped normal.

Parameters:

int pos

The position of the first vertex to be deleted.

int num=1

The number of vertices & edges to delete.

int edir=1

There are two choices for the edges to be deleted: we can delete the edges going from pos to pos+1, pos+1 to pos+2, … pos+num-1 to pos+num, or we can delete pos-1 to pos, pos to pos+1, … pos+num-2 to pos+num-1. (pos+num-1 is the last vertex deleted.) That is to say, we can delete the edges "before" the vertices we’re deleting, or we can delete the edges "after" them. If edir is positive, we delete the edges after the vertices. If it’s negative, we delete the edges before. Keep in mind that this also affects edge visibility and selection information on this face.

bool fixtri=TRUE

This parameter is available in release 3.0 and later only.

This argument indicates how far Delete should go in fixing the triangulation. Delete will always correct the values of the tri array to correspond to the reduced-degree face. If fixtri is true, it will also delete those triangles that have collapsed because they had two vertices in the deleted region. If not, it will leave these triangles with overlapping vertices, as in (0,0,2).

Return Value:

Delete returns TRUE if fixtri is FALSE. If fixtri is TRUE, Delete will return TRUE if it successfully corrected the triangulation, or FALSE if there was a problem. If FALSE is returned, the triangulation will need to be revised with a call to RetriangulateFace.

Prototype:

RotateStart(int newstart);

Remarks:

This method is available in release 2.5 and later only.

Re-indexes the vertices and edges so that the vertex in position newstart becomes the new first vertex. Triangulation is also corrected. Mapping coordinates and vertex colors are corrected automatically.

Prototype:

void Flip();

Remarks:

This method is available in release 2.5 and later only.

Reverses order of verts, effectively inverting the face. vtx[0] remains unchanged, but vertex deg-1 becomes vertex 1, etc. Note that this operation wreaks havoc on nearby edges and should be used with caution.

Prototype:

int VertIndex(int vv, int ee=-1);

Remarks:

Returns the position of vertex vv in this face’s list of vertices. For a given face fc, if fc.vtx[i] = vv, fc.VertIndex (vv) = i.

Sometimes a single vertex from the MNMesh’s MNVert list can be referenced more than once by a single face. The picture below illustrates this problem. The small triangle is actually outside of the face, and the vertex at the top of it is referenced twice by the face. Thus an additional edge parameter can be accepted. If ee is -1, it is ignored, and the first instance of vv is used. If ee>-1, this method looks for the instance of vv that starts out edge ee. Thus if fc.vtx[i] = vv and fc.vtx[j] = vv, but fc.edg[i] != ee and fc.edg[j] = ee, j is returned.

IMPORTANT: If no vertex is found matching the given parameters, this method generates an assertion failure. Please be sure that vertex vv is actually on the face (and that edge ee follows it if ee is not -1) before using this method.

Prototype:

int EdgeIndex(int ee, int vv=-1);

Remarks:

Returns the position of edge ee in this face’s list of edges. For a given face fc, if fc.edg[i] = ee, fc.EdgeIndex (ee) = i.

Sometimes a single edge from the MNMesh’s MNEdge list can be referenced more than once by a single face. The small rectangle is actually outside of the face, and the edge above it is referenced twice by the face, once in each direction. Thus an additional vertex parameter can be accepted. If vv is -1, it is ignored, and the first instance of ee is used. If vv>-1, this method looks for the instance of ee that starts out with vertex vv. Thus if fc.edg[i] = ee and fc.edg[j] = ee, but fc.vtx[i] != vv and fc.vtx[j] = vv, j is returned.

IMPORTANT: If no edge is found matching the given parameters, this method generates an assertion failure. Please be sure that edge ee is actually on the face (and that vertex vv follows it if vv is not -1) before using this method.

Prototype:

ReplaceVert(int ov, int nv, int ee=-1);

Remarks:

This method is available in release 2.5 and later only.

Replaces vertex ov with vertex nv in the list of vertices. It is possible for a face to reference the same vertex more than once, however the combination of a vertex followed by a specified edge is unique. Therefore if ee<0, all instances of ov are replaced by nv, but if not, only the instance of ov followed by ee is replaced.

Prototype:

ReplaceEdge(int oe, int ne, int vv=-1);

Remarks:

Replaces edge oe with edge ne in the list of edges. It is possible for a face to reference the same edge twice, however the combination of an edge preceded by a specified vertex is unique. Therefore if vv<0, all instances of oe are replaced by ne, but if not, only the instance of oe preceded by vv is replaced.

Prototype:

void MNDebugPrint(bool triprint=FALSE, bool hinfo=TRUE);

Remarks:

This method is available in release 2.5 and later only.

Uses DebugPrint to print out face information to the Debug Results window in DevStudio. The information consists of the vertices and edges used by this face. It is generally a good idea to put in a DebugPrint immediately before this with the index of the edge, so you know which one is being printed out:

DebugPrint("Face %d: ", fid);

F(fid)->MNDebugPrint();

Parameters:

bool triprint=FALSE

Print out triangulation information.

bool hinfo=TRUE

Print out hidden vertex information.

Prototype:

MNFace & operator=(const MNFace & from);

Remarks:

Assignment operator. Copies all information from "from", including triangulation, hidden vertices, flags, smoothing & material info, and "track".

Prototype:

int &operator[](int i);

Remarks:

This method is available in release 4.0 and later only.

Access operator.

Default Implementation:

{ return vtx[i]; }

Prototype:

const int &operator[](int i) const;

Remarks:

This method is available in release 4.0 and later only.

Access operator.

Default Implementation:

{ return vtx[i]; }