khanat-opennel-code/code/nel/tools/3d/plugin_max/nel_patch_lib/nel_patch_mesh.cpp

3153 lines
78 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
#include "nel_patch_mesh.h"
#include "nel/misc/time_nl.h"
#include "vertex_neighborhood.h"
#include "../nel_3dsmax_shared/nel_3dsmax_shared.h"
#include "nel/3d/zone_symmetrisation.h"
// For MAX_RELEASE
#include <plugapi.h>
using namespace NL3D;
using namespace NLMISC;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif max
//#ifndef min
//#define min(a,b) (((a) < (b)) ? (a) : (b))
//#endif min
#define PBLOCK_REF 0
#ifdef USE_CACHE
#ifndef NDEBUG
#define DEBUG_PIPELINE
#endif // NDEBUG
#endif // USE_CACHE
float bindWhere[BIND_COUNT]=
{
0.25f,
0.75f,
0.5f,
0.5f
};
#define RK_APPDATA_TILEFILE 0
#define RK_APPDATA_LAND 1
#define REGKEY_TILEDIT "Software\\Nevrax\\Ryzom\\Tile_Edit"
//#define CHECK_VALIDITY // check validity
// Default constructor, allocate the array
CPatchMeshData::CPatchMeshData ()
{
// Get a global allocator
CPatchAllocator& _Allocator=GetAllocator ();
_UIPatch=_Allocator.AllocPatch.allocate();
_UIVertex=_Allocator.AllocVertex.allocate();
_MapHitToTileIndex=_Allocator.AllocInt.allocate();
}
// Copy constructor, allocate the array
CPatchMeshData::CPatchMeshData (const CPatchMeshData& src)
{
this->CPatchMeshData::CPatchMeshData ();
this->operator= (src);
}
// Destructor
CPatchMeshData::~CPatchMeshData ()
{
// Get a global allocator
CPatchAllocator& _Allocator=GetAllocator ();
_Allocator.AllocPatch.free (_UIPatch);
_Allocator.AllocVertex.free (_UIVertex);
_Allocator.AllocInt.free (_MapHitToTileIndex);
}
// Copy
CPatchMeshData& CPatchMeshData::operator= (const CPatchMeshData& src)
{
*_UIPatch=*src._UIPatch;
*_UIVertex=*src._UIVertex;
*_MapHitToTileIndex=*src._MapHitToTileIndex;
return *this;
}
NL3D::CTileBank bank;
std::string GetBankPathName ()
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_TILEDIT, 0, KEY_READ, &hKey)==ERROR_SUCCESS)
{
char path[256];
DWORD len=256;
DWORD type;
if (RegQueryValueEx(hKey, "Bank Path", 0, &type, (LPBYTE)path, &len)==ERROR_SUCCESS)
return std::string (path);
RegCloseKey (hKey);
}
return "";
}
int GetBankTileSetSet ()
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_TILEDIT, 0, KEY_READ, &hKey)==ERROR_SUCCESS)
{
int tileSetSet;
DWORD len=256;
DWORD type;
if (RegQueryValueEx(hKey, "Tileset Set", 0, &type, (LPBYTE)&tileSetSet, &len)==ERROR_SUCCESS)
return tileSetSet;
RegCloseKey (hKey);
}
return -1;
}
void SetBankPathName (const std::string& path)
{
HKEY hKey;
if (RegCreateKey(HKEY_CURRENT_USER, REGKEY_TILEDIT, &hKey)==ERROR_SUCCESS)
{
RegSetValueEx(hKey, "Bank Path", 0, REG_SZ, (LPBYTE)path.c_str(), path.length()+1);
RegCloseKey (hKey);
}
}
void SetBankTileSetSet (int tileSetSet)
{
HKEY hKey;
if (RegCreateKey(HKEY_CURRENT_USER, REGKEY_TILEDIT, &hKey)==ERROR_SUCCESS)
{
RegSetValueEx(hKey, "Tileset Set", 0, REG_DWORD, (LPBYTE)&tileSetSet, 4);
RegCloseKey (hKey);
}
}
// RPatchMesh --------------------------------------------------------------------------------------------------------------------------------------------
// Constructeur
RPatchMesh::RPatchMesh (PatchMesh *pmesh)
{
// Invalidate
ValidGeom=NEVER;
ValidTopo=NEVER;
ValidTexmap=NEVER;
ValidSelect=NEVER;
ValidDisplay=NEVER;
ValidBindingInfo=FOREVER;
ValidBindingPos=FOREVER;
rTess.ModeTile=true;
rTess.KeepMapping=false;
rTess.TransitionType=1;
SetSelLevel (EP_OBJECT);
rTess.TileTesselLevel=0;
build=-1;
paintHack=false;
if (pmesh)
{
// Patches
SetNumPatches (pmesh->getNumPatches());
// Vertices
SetNumVerts (pmesh->getNumVerts());
}
// Getback the binding informations
for (int v=0; v<pmesh->hooks.Count(); v++)
{
int hookPoint=pmesh->hooks[v].hookPoint;
int hookEdge=pmesh->hooks[v].hookEdge;
int hookPatch=pmesh->hooks[v].hookPatch;
AddHook (hookPoint, hookEdge, *pmesh);
}
}
RPatchMesh::RPatchMesh ()
{
// Set level
SetSelLevel (EP_OBJECT);
build=-1;
rTess.TransitionType=1;
paintHack=false;
// Invalidate
ValidGeom=NEVER;
ValidTopo=NEVER;
ValidTexmap=NEVER;
ValidSelect=NEVER;
ValidDisplay=NEVER;
ValidBindingInfo=FOREVER;
ValidBindingPos=FOREVER;
rTess.ModeTile=true;
rTess.KeepMapping=false;
rTess.TransitionType=1;
SetSelLevel (EP_OBJECT);
rTess.TileTesselLevel=0;
build=-1;
paintHack=false;
};
RPatchMesh::~RPatchMesh ()
{
};
// Check if a vertex is in a seg
bool IsVertexInEdge (int nVert, int nSeg, const PatchMesh& patch)
{
if ((patch.edges[nSeg].v1==nVert)||(patch.edges[nSeg].v2==nVert))
return true;
else
return false;
}
// return other vertex in edge
int GetOtherVertex (int nVert, int nSeg, const PatchMesh& patch)
{
if (patch.edges[nSeg].v1==nVert)
return patch.edges[nSeg].v2;
else
{
nlassert (patch.edges[nSeg].v2==nVert);
return patch.edges[nSeg].v1;
}
}
// Check if two vertex are joined by a edge
int IsVerticesJoined (int nVert0, int nVert1, const CVertexNeighborhood& tab, const PatchMesh& patch)
{
// Count of neigbor for vertex 0
uint listSize=tab.getNeighborCount (nVert0);
// List of neigbor
const uint* pList=tab.getNeighborList (nVert0);
// For each neigbor
for (uint n=0; n<listSize; n++)
{
// If the vertex is on this edge, return the edge number
if (IsVertexInEdge (nVert1, pList[n], patch))
return pList[n];
}
return -1;
}
// Check if two vertex are joined by a edge
bool IsVerticesJoined2 (int nVert0, int nVert1, int& nVert2, int& nEdge0, int& nEdge1, const CVertexNeighborhood& tab, const PatchMesh& patch)
{
int nCount=0;
//
if (IsVerticesJoined (nVert0, nVert1, tab, patch)!=-1)
return false;
// Count of neigbor for vertex 0
uint listSize=tab.getNeighborCount (nVert0);
// List of neigbor
const uint* pList=tab.getNeighborList (nVert0);
// For each neigbor
for (uint n=0; n<listSize; n++)
{
// Index of the next vertex of this edge
int nNextVert=(patch.edges[pList[n]].v1==nVert0)?patch.edges[pList[n]].v2:patch.edges[pList[n]].v1;
if (nNextVert!=-1)
{
// The two vertex are joined ?
int nEdge=IsVerticesJoined (nNextVert, nVert1, tab, patch);
// Yes !
if (nEdge!=-1)
{
// One more
nCount++;
nVert2=nNextVert;
nEdge0=nEdge;
nEdge1=pList[n];
}
}
}
return (nCount==1);
}
// Check if a vertex is in a patch
bool IsVertexInPatch (int nVert, int nPatch, const PatchMesh& patch)
{
for (int i=0; i<4; i++)
{
if (patch.patches[nPatch].v[i]==nVert)
return true;
}
return false;
}
// Check binding
int CheckBind (int nVert, int nSeg, int& v0, int& v1, int& v2, int& v3, const CVertexNeighborhood& tab, const PatchMesh& patch, bool bAssert, bool bCreate)
{
int config=-1;
// Check config 1
// v0 ******* nVert ******* v1
// *************************
v0=patch.edges[nSeg].v1;
v1=patch.edges[nSeg].v2;
// Valid edge to bind on
if (v0==-1)
{
if (bAssert)
nlassert (0);
}
else
{
if (v1==-1)
{
if (bAssert)
nlassert (0);
}
else
{
#if (MAX_RELEASE < 4000)
if ((patch.edges[nSeg].patch2!=-1)&&bCreate)
{
if (bAssert)
nlassert (0);
}
else
#else // (MAX_RELEASE < 4000)
if ((patch.edges[nSeg].patches.Count()>1)&&bCreate)
{
if (bAssert)
nlassert (0);
}
else if (patch.edges[nSeg].patches.Count() > 0)
#endif // (MAX_RELEASE < 4000)
{
// config 1?
int nSeg0=IsVerticesJoined (v0, nVert, tab, patch);
int nSeg1=IsVerticesJoined (v1, nVert, tab, patch);
if ((nSeg0!=-1)&&(nSeg1!=-1))
{
// additionnal check.
#if (MAX_RELEASE < 4000)
if ((patch.edges[nSeg0].patch2==-1)&&(patch.edges[nSeg1].patch2==-1))
{
if (!IsVertexInPatch (nVert, patch.edges[nSeg].patch1, patch))
config=0;
}
#else // (MAX_RELEASE < 4000)
if ((patch.edges[nSeg0].patches.Count()<2)&&(patch.edges[nSeg1].patches.Count()<2))
{
if (!IsVertexInPatch (nVert, patch.edges[nSeg].patches[0], patch))
config=0;
}
#endif // (MAX_RELEASE < 4000)
}
if (config==-1)
{
// Check config 2
// v0 **** v2 **** nVert **** v3 **** v1
// ***********************************
int nEdge0;
int nEdge1;
int nEdge2;
int nEdge3;
if (IsVerticesJoined2 (v0, nVert, v2, nEdge0, nEdge1, tab, patch)&&
IsVerticesJoined2 (v1, nVert, v3, nEdge2, nEdge3, tab, patch))
{
// additionnal check
if ((v2!=v3)&&
(nEdge0!=nEdge1)&&
(nEdge0!=nEdge2)&&
(nEdge0!=nEdge3)&&
(nEdge1!=nEdge2)&&
(nEdge1!=nEdge3)&&
(nEdge2!=nEdge3)&&
#if (MAX_RELEASE < 4000)
(patch.edges[nEdge0].patch2==-1)&&
(patch.edges[nEdge1].patch2==-1)&&
(patch.edges[nEdge2].patch2==-1)&&
(patch.edges[nEdge3].patch2==-1)&&
(!IsVertexInPatch (nVert, patch.edges[nSeg].patch1, patch))&&
(!IsVertexInPatch (v2, patch.edges[nSeg].patch1, patch))&&
(!IsVertexInPatch (v3, patch.edges[nSeg].patch1, patch)))
#else // (MAX_RELEASE < 4000)
(patch.edges[nEdge0].patches.Count()<2)&&
(patch.edges[nEdge1].patches.Count()<2)&&
(patch.edges[nEdge2].patches.Count()<2)&&
(patch.edges[nEdge3].patches.Count()<2)&&
(!IsVertexInPatch (nVert, patch.edges[nSeg].patches[0], patch))&&
(!IsVertexInPatch (v2, patch.edges[nSeg].patches[0], patch))&&
(!IsVertexInPatch (v3, patch.edges[nSeg].patches[0], patch)))
#endif // (MAX_RELEASE < 4000)
{
config=1;
}
}
}
if (config==-1)
{
// No config
if (bAssert)
nlassert (0);
}
}
}
}
return config;
}
// Patchmesh Check validity (debug stuff)
bool RPatchMesh::Validity (const PatchMesh& patch, bool bAssert)
{
#ifdef CHECK_VALIDITY
bool bRet=true;
// Check patches count
int nPatchCount=patch.numPatches;
int nPatchUICount=getUIPatchSize();
if (nPatchCount!=nPatchUICount)
{
if (bAssert)
nlassert (0); // Not the same patch count
bRet=false;
}
// Check vertices count
int nVertCount=patch.numVerts;
int nVertUICount=getUIVertexSize();
if (nVertCount!=nVertUICount)
{
if (bAssert)
nlassert (0); // Not the same vertices count
bRet=false;
}
// Static table to avoid alloc prb
CVertexNeighborhood& tab=vertexNeighborhoodGlobal;
tab.build (patch);
// Check binding info in vertices
for (int nVertex=0; nVertex<(int)getUIVertexSize(); nVertex++)
{
// Binding on this vertex ?
if (getUIVertex(nVertex).Binding.bBinded)
{
// Check # of the patch
int nPatchNumber=getUIVertex(nVertex).Binding.nPatch;
if ((nPatchNumber>=nPatchUICount)||(nPatchNumber<0))
{
if (bAssert)
nlassert (0); // # patch invalid in binding info
bRet=false;
}
// Check # of the edge
int nEdgeNumber=getUIVertex(nVertex).Binding.nEdge;
if ((nEdgeNumber>=4)||(nEdgeNumber<0))
{
if (bAssert)
nlassert (0); // # edge invalid in binding info
bRet=false;
}
// Check fWhere
typeBind type = (typeBind)(getUIVertex(nVertex).Binding.nType);
if ((type!=BIND_25)&&
(type!=BIND_50)&&
(type!=BIND_75)&&
(type!=BIND_SINGLE))
{
if (bAssert)
nlassert (0); // fWhere value invalid in binding info
bRet=false;
}
// Primary vertex
int nPrim=getUIVertex(nVertex).Binding.nPrimVert;
if ((nPrim<0)||(nPrim>=patch.numVerts))
{
if (bAssert)
nlassert(0);
bRet=false;
if (nPrim!=nVertex)
{
if (!getUIVertex(nPrim).Binding.bBinded)
{
if (bAssert)
nlassert(0);
bRet=false;
}
if (getUIVertex(nPrim).Binding.nEdge!=(uint)nEdgeNumber)
{
if (bAssert)
nlassert(0);
bRet=false;
}
if (getUIVertex(nPrim).Binding.nPatch!=(uint)nPatchNumber)
{
if (bAssert)
nlassert(0);
bRet=false;
}
if ((getUIVertex(nPrim).Binding.nPrimVert==BIND_50)||(getUIVertex(nPrim).Binding.nPrimVert==BIND_SINGLE))
{
if (bAssert)
nlassert(0);
bRet=false;
}
}
}
// Check geom
int v0, v1, v2, v3;
switch (CheckBind (nPrim, patch.patches[nPatchNumber].edge[nEdgeNumber], v0, v1, v2, v3, tab, patch, bAssert, false))
{
case 0:
if (type!=BIND_SINGLE)
{
if (bAssert)
nlassert(0);
bRet=false;
}
break;
case 1:
if (nVertex!=nPrim)
{
if (v2==nVertex)
{
if (type!=BIND_25)
{
if (bAssert)
nlassert(0);
bRet=false;
}
}
else if (v3==nVertex)
{
if (type!=BIND_75)
{
if (bAssert)
nlassert(0);
bRet=false;
}
}
else
{
if (type!=BIND_50)
{
if (bAssert)
nlassert(0);
bRet=false;
}
}
}
break;
}
}
}
// Check mode tile
int nSelTileSize=tileSel.GetSize();
int nTileSize=getUIPatchSize()*NUM_TILE_SEL;
if (nSelTileSize!=nTileSize)
{
if (bAssert)
nlassert(0);
bRet=false;
}
// Check count of it index
if (rTess.TileTesselLevel>=0)
{
int nFaceCount=mesh.numFaces;
int nHitCount=_Data._MapHitToTileIndex->size();
if (nFaceCount!=nHitCount)
{
if (bAssert)
nlassert (0);
bRet=false;
}
}
// Return the bad news...
return bRet;
#else // CHECK_VALIDITY
return true;
#endif
}
static Point3 InterpCenter(Point3 e1, Point3 i1, Point3 i2, Point3 e2, Point3 *v1 = NULL, Point3 *v2 = NULL, Point3 *v3 = NULL, Point3 *v4 = NULL)
{
Point3 e1i1 =(e1 + i1) / 2.0f;
Point3 i1i2 =(i1 + i2) / 2.0f;
Point3 i2e2 =(i2 + e2) / 2.0f;
Point3 a =(e1i1 + i1i2) / 2.0f;
Point3 b =(i1i2 + i2e2) / 2.0f;
if (v1)
*v1 = e1i1;
if (v2)
*v2 = a;
if (v3)
*v3 = b;
if (v4)
*v4 = i2e2;
return (a + b) / 2.0f;
}
// Update binded vertices's position
void RPatchMesh::UpdateBindingPos (PatchMesh& patch)
{
// Check validity
#ifndef NDEBUG
Validity (patch, true);
#endif // NDEBUG
// Vertex count
int nVertexCount=patch.getNumVerts ();
// Pointer
uint vertSize=getUIVertexSize();
for (uint nV=0; nV<vertSize; nV++)
{
// Pointer on the patch
UI_VERTEX* pVertex=&getUIVertex (nV);
// Binded?
if (pVertex->Binding.bBinded)
{
static const float fU[4]={0.f, 1.f, 0.f, -1.f};
static const float fV[4]={1.f, 0.f, -1.f, 0.f};
static const float fUadd[4]={0.f, 0.f, 1.f, 1.f};
static const float fVadd[4]={0.f, 1.f, 1.f, 0.f};
// Calcule new position of the vertex
int nEdge=patch.patches[pVertex->Binding.nPatch].edge[pVertex->Binding.nEdge];
PatchEdge &edge=patch.edges[nEdge];
// Save
Point3 vOld=patch.verts[nV].p;
switch (pVertex->Binding.nType)
{
case BIND_25:
{
Point3 v0, v1, v2, v3, v4;
v2=InterpCenter(patch.verts[edge.v1].p, patch.vecs[edge.vec12].p, patch.vecs[edge.vec21].p,
patch.verts[edge.v2].p, &v0, &v1, &v3, &v4);
// Final interpolation
patch.verts[nV].p=InterpCenter(patch.verts[edge.v1].p, v0, v1, v2,
&patch.vecs[pVertex->Binding.nBefore2].p, &patch.vecs[pVertex->Binding.nBefore].p,
&patch.vecs[pVertex->Binding.nAfter].p, &patch.vecs[pVertex->Binding.nAfter2].p);
}
break;
case BIND_50:
patch.verts[nV].p=InterpCenter(patch.verts[edge.v1].p, patch.vecs[edge.vec12].p, patch.vecs[edge.vec21].p,
patch.verts[edge.v2].p, NULL, NULL, NULL, NULL);
break;
case BIND_75:
{
Point3 v0, v1, v2, v3, v4;
v2=InterpCenter(patch.verts[edge.v1].p, patch.vecs[edge.vec12].p, patch.vecs[edge.vec21].p,
patch.verts[edge.v2].p, &v0, &v1, &v3, &v4);
// Final interpolation
patch.verts[nV].p=InterpCenter(v2, v3, v4, patch.verts[edge.v2].p,
&patch.vecs[pVertex->Binding.nBefore2].p, &patch.vecs[pVertex->Binding.nBefore].p,
&patch.vecs[pVertex->Binding.nAfter].p, &patch.vecs[pVertex->Binding.nAfter2].p);
}
break;
case BIND_SINGLE:
patch.verts[nV].p=InterpCenter(patch.verts[edge.v1].p, patch.vecs[edge.vec12].p, patch.vecs[edge.vec21].p,
patch.verts[edge.v2].p, &patch.vecs[pVertex->Binding.nBefore2].p, &patch.vecs[pVertex->Binding.nBefore].p,
&patch.vecs[pVertex->Binding.nAfter].p, &patch.vecs[pVertex->Binding.nAfter2].p);
break;
default:
nlassert (0);
}
patch.vecs[pVertex->Binding.nT].p += patch.verts[nV].p-vOld;
}
}
patch.computeInteriors();
patch.InvalidateGeomCache();
}
// Build internal binding info
void RPatchMesh::UpdateBindingInfo (PatchMesh& patch)
{
// Make tab vert to edge list
// Static table to avoid alloc prb
CVertexNeighborhood& tab=vertexNeighborhoodGlobal;
tab.build (patch);
for (int n=0; n<patch.numVerts; n++)
{
if (getUIVertex (n).Binding.bBinded)
{
int v0=patch.edges[patch.patches[getUIVertex (n).Binding.nPatch].edge[getUIVertex (n).Binding.nEdge]].v1;
int v1=patch.edges[patch.patches[getUIVertex (n).Binding.nPatch].edge[getUIVertex (n).Binding.nEdge]].v2;
int vB=-1;
int vA=-1;
int vT=-1;
// Count of neigbor for vertex n
uint listSize=tab.getNeighborCount (n);
// List of neigbor
const uint* pList=tab.getNeighborList (n);
// For each neigbor
for (uint nn=0; nn<listSize; nn++)
{
if (getUIVertex (n).Binding.nType==BIND_25)
{
if (IsVertexInEdge (v0, pList[nn], patch))
{
nlassert (vB==-1);
vB=pList[nn];
}
else if (IsVertexInEdge (getUIVertex (n).Binding.nPrimVert, pList[nn], patch))
{
nlassert (vA==-1);
vA=pList[nn];
}
else
{
vT=pList[nn];
}
}
else if (getUIVertex (n).Binding.nType==BIND_75)
{
if (IsVertexInEdge (getUIVertex (n).Binding.nPrimVert, pList[nn], patch))
{
nlassert (vB==-1);
vB=pList[nn];
}
else if (IsVertexInEdge (v1, pList[nn], patch))
{
nlassert (vA==-1);
vA=pList[nn];
}
else
{
vT=pList[nn];
}
}
else if (getUIVertex (n).Binding.nType==BIND_50)
{
int nother=GetOtherVertex (n, pList[nn], patch);
nlassert (nother!=-1);
if ((getUIVertex (nother).Binding.bBinded&&
(getUIVertex (nother).Binding.nType==BIND_25)&&
(getUIVertex (nother).Binding.nPrimVert==(uint)n)))
{
nlassert (vB==-1);
vB=pList[nn];
}
else if ((getUIVertex (nother).Binding.bBinded&&
(getUIVertex (nother).Binding.nType==BIND_75)&&
(getUIVertex (nother).Binding.nPrimVert==(uint)n)))
{
nlassert (vA==-1);
vA=pList[nn];
}
else
{
vT=pList[nn];
}
}
else if (getUIVertex (n).Binding.nType==BIND_SINGLE)
{
int nother=GetOtherVertex (n, pList[nn], patch);
nlassert (nother!=-1);
if (IsVertexInEdge (v0, pList[nn], patch))
{
nlassert (vB==-1);
vB=pList[nn];
}
else if (IsVertexInEdge (v1, pList[nn], patch))
{
nlassert (vA==-1);
vA=pList[nn];
}
else
{
vT=pList[nn];
}
}
}
nlassert (vB!=-1);
nlassert (vA!=-1);
nlassert (vT!=-1);
getUIVertex (n).Binding.nBefore=(patch.edges[vB].v1==n)?patch.edges[vB].vec12:patch.edges[vB].vec21;
getUIVertex (n).Binding.nAfter=(patch.edges[vA].v1==n)?patch.edges[vA].vec12:patch.edges[vA].vec21;
getUIVertex (n).Binding.nT=(patch.edges[vT].v1==n)?patch.edges[vT].vec12:patch.edges[vT].vec21;
getUIVertex (n).Binding.nBefore2=(patch.edges[vB].v1==n)?patch.edges[vB].vec21:patch.edges[vB].vec12;
getUIVertex (n).Binding.nAfter2=(patch.edges[vA].v1==n)?patch.edges[vA].vec21:patch.edges[vA].vec12;
}
}
}
// Update binding
void RPatchMesh::UpdateBinding (PatchMesh& patch, TimeValue t)
{
if (!ValidBindingInfo.InInterval (t))
{
ValidBindingInfo=FOREVER;
UpdateBindingInfo (patch);
}
if (!ValidBindingPos.InInterval (t))
{
ValidBindingPos=FOREVER;
UpdateBindingPos (patch);
}
}
// Fill the binding info for a vertex. Don't forget to call UpdateBindingInfo after
void RPatchMesh::BindingVertex (int nVertex, int nPatch, int nEdge, int nPrimary, typeBind nType)
{
// Some check
nlassert (nVertex>=0);
nlassert (nVertex<(sint)getUIVertexSize());
nlassert (nPrimary>=0);
nlassert (nPrimary<(sint)getUIVertexSize());
nlassert (nPatch>=0);
nlassert (nPatch<(sint)getUIPatchSize());
nlassert (nEdge>=0);
nlassert (nEdge<4);
nlassert ((nType==BIND_25)||(nType==BIND_50)||(nType==BIND_75)||(nType==BIND_SINGLE));
// Go...
getUIVertex (nVertex).Binding.bBinded=true;
getUIVertex (nVertex).Binding.nPatch=nPatch;
getUIVertex (nVertex).Binding.nEdge=nEdge;
getUIVertex (nVertex).Binding.nType=nType;
getUIVertex (nVertex).Binding.nPrimVert=nPrimary;
getUIVertex (nVertex).Binding.nBefore=-1;
getUIVertex (nVertex).Binding.nAfter=-1;
getUIVertex (nVertex).Binding.nT=-1;
getUIVertex (nVertex).Binding.nBefore2=-1;
getUIVertex (nVertex).Binding.nAfter2=-1;
}
// Unbind a vertex
void RPatchMesh::UnBindingVertex (int nVertex)
{
getUIVertex (nVertex).Binding.bBinded=false;
getUIVertex (nVertex).Binding.nAfter=-1;
getUIVertex (nVertex).Binding.nAfter2=-1;
getUIVertex (nVertex).Binding.nBefore=-1;
getUIVertex (nVertex).Binding.nBefore2=-1;
getUIVertex (nVertex).Binding.nT=-1;
}
// Resize vertex buffer
void RPatchMesh::SetNumVerts (int nVert)
{
int nOldSize=getUIVertexSize();
resizeUIVertex (nVert);
for (int n=nOldSize; n<nVert; n++)
{
getUIVertex (n).Init ();
}
}
// Resize patch buffer
void RPatchMesh::SetNumPatches (int nPatch)
{
int nOldSize=getUIPatchSize();
resizeUIPatch (nPatch);
for (int n=nOldSize; n<nPatch; n++)
{
getUIPatch (n).Init ();
}
// Resize sel array
tileSel.SetSize (NUM_TILE_SEL*nPatch, 1);
}
// Subdivide both way
void RPatchMesh::Subdivide (int nPatch, int nV0, int nV1, int nV2, int nV3, int nCenter, int nFirstPatch, PatchMesh& patch)
{
// Subdivide patch
int nOldTileCount=(1<<getUIPatch (nPatch).NbTilesU)*(1<<getUIPatch (nPatch).NbTilesV);
int nOldVertexCount=((1<<getUIPatch (nPatch).NbTilesU)+1)*((1<<getUIPatch (nPatch).NbTilesV)+1);
int nTileU=max (0, (int)getUIPatch (nPatch).NbTilesU-1);
int nTileV=max (0, (int)getUIPatch (nPatch).NbTilesV-1);
// Copy info
int nTileCountU=1<<nTileU;
int nTileCountV=1<<nTileV;
// * 0
// Patch ptr
UI_PATCH *pPatch=&getUIPatch (nFirstPatch);
// Init patch info without intialize tabl
pPatch->Init (nTileU, nTileV, true);
int v;
for(v=0; v<nTileCountV; v++)
for(int u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=u+v*nTileCountU;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=u+(2*nTileCountU*v);
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
}
for(v=0; v<nTileCountV+1; v++)
for(int u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=u+v*(nTileCountU+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=u+((2*nTileCountU+1)*v);
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (0);
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (3);
// * 1
// Patch ptr
pPatch++;
// Init patch info without intialize tabl
pPatch->Init (nTileV, nTileU, true);
for(v=0; v<nTileCountV; v++)
for(int u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=(nTileCountV-1-v)+u*nTileCountV;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=u+(2*nTileCountU*(nTileCountV+v));
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
/*pPatch->Tile[nTile]=getUIPatch (nPatch).Tile[nOldTile];
pPatch->Tile[nTile].Rotate=(getUIPatch (nPatch).Tile[nOldTile].Rotate+3)&3;*/
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
pPatch->getTileDesc (nTile).rotate (3);
}
for(v=0; v<nTileCountV+1; v++)
for(int u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=(nTileCountV-v)+u*(nTileCountV+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=u+((2*nTileCountU+1)*(nTileCountV+v));
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (0);
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (1);
// * 2
// Patch ptr
pPatch++;
// Init patch info without intialize tabl
pPatch->Init (nTileU, nTileV, true);
for(v=0; v<nTileCountV; v++)
for(int u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=(nTileCountU-1-u)+(nTileCountV-1-v)*nTileCountU;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=nTileCountU+u+(2*nTileCountU*(nTileCountV+v));
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
//pPatch->Tile[nTile].Rotate=(getUIPatch (nPatch).Tile[nOldTile].Rotate+2)&3;
pPatch->getTileDesc (nTile).rotate (2);
}
for(v=0; v<nTileCountV+1; v++)
for(int u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=(nTileCountU-u)+(nTileCountV-v)*(nTileCountU+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=nTileCountU+u+((2*nTileCountU+1)*(nTileCountV+v));
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (2);
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (1);
// * 3
// Patch ptr
pPatch++;
// Init patch info without intialize tabl
pPatch->Init (nTileV, nTileU, true);
for(v=0; v<nTileCountV; v++)
for(int u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=v+(nTileCountU-1-u)*nTileCountV;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=nTileCountU+u+(2*nTileCountU*v);
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
//pPatch->Tile[nTile].Rotate=(getUIPatch (nPatch).Tile[nOldTile].Rotate+1)&3;
pPatch->getTileDesc (nTile).rotate (1);
}
for(v=0; v<nTileCountV+1; v++)
for(int u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=v+(nTileCountU-u)*(nTileCountV+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=nTileCountU+u+((2*nTileCountU+1)*v);
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (3);
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (2);
// Update binding info
for (int i=0; i<(int)getUIVertexSize(); i++)
{
if (getUIVertex (i).Binding.bBinded)
{
if ((int)getUIVertex (i).Binding.nPatch==nPatch)
{
UnBindingVertex (i);
}
}
}
UnbindRelatedPatch (nPatch, patch);
InvalidateBindingInfo ();
}
// Subdivide edge 1 and 3
void RPatchMesh::SubdivideU (int nPatch, int nV0, int nV1, int nFirstPatch, PatchMesh& patch)
{
// Subdivide patch
int nOldTileCount=(1<<getUIPatch (nPatch).NbTilesU)*(1<<getUIPatch (nPatch).NbTilesV);
int nOldVertexCount=((1<<getUIPatch (nPatch).NbTilesU)+1)*((1<<getUIPatch (nPatch).NbTilesV)+1);
int nTileU=(int)getUIPatch (nPatch).NbTilesV;
int nTileV=max (0, (int)getUIPatch (nPatch).NbTilesU-1);
for (int nNewPatch=nFirstPatch; nNewPatch<nFirstPatch+2; nNewPatch++)
{
// Patch ptr
UI_PATCH *pPatch=&getUIPatch (nNewPatch);
// New patch number
int nNewPatchNum=nNewPatch-nFirstPatch;
// Coord of the subpatch
int nU=nNewPatchNum;
// Init patch info without intialize tabl
pPatch->Init (nTileU, nTileV, true);
// Copy info
int nTileCountU=1<<nTileU;
int nTileCountV=1<<nTileV;
int v;
for(v=0; v<nTileCountV; v++)
for(int u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=u+v*nTileCountU;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=v+nTileCountV*nU+(nTileCountU-1-u)*nTileCountV*2;
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
//pPatch->Tile[nTile].Rotate=(getUIPatch (nPatch).Tile[nOldTile].Rotate+3)&3;
pPatch->getTileDesc (nTile).rotate (3);
}
for(v=0; v<nTileCountV+1; v++)
for(int u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=u+v*(nTileCountU+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=v+nTileCountV*nU+(nTileCountU-u)*(nTileCountV*2+1);
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize ());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
if (nNewPatch==nFirstPatch)
{
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (0);
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (1);
pPatch->getEdge (2)=getUIPatch (nPatch).getEdge (3);
}
else
{
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (1);
pPatch->getEdge (1)=getUIPatch (nPatch).getEdge (2);
pPatch->getEdge (2)=getUIPatch (nPatch).getEdge (3);
}
}
// Update binding info
for (int i=0; i<(int)getUIVertexSize(); i++)
{
if ((getUIVertex (i).Binding.bBinded)&&((int)getUIVertex (i).Binding.nPatch==nPatch))
{
if (getUIVertex (i).Binding.nEdge&1)
{
UnBindingVertex (i);
}
else
{
if (getUIVertex (i).Binding.nEdge==0)
{
getUIVertex (i).Binding.nPatch=nFirstPatch;
getUIVertex (i).Binding.nEdge=3;
}
else
{
nlassert (getUIVertex (i).Binding.nEdge==2);
getUIVertex (i).Binding.nPatch=nFirstPatch+1;
getUIVertex (i).Binding.nEdge=1;
}
}
}
}
UnbindRelatedPatch (nPatch, patch);
InvalidateBindingInfo ();
}
// Subdivide edge 0 and 2
void RPatchMesh::SubdivideV (int nPatch, int nV0, int nV1, int nFirstPatch, PatchMesh& patch)
{
// Subdivide patch
int nOldTileCount=(1<<getUIPatch (nPatch).NbTilesU)*(1<<getUIPatch (nPatch).NbTilesV);
int nOldVertexCount=((1<<getUIPatch (nPatch).NbTilesU)+1)*((1<<getUIPatch (nPatch).NbTilesV)+1);
int nTileU=getUIPatch (nPatch).NbTilesU;
int nTileV=max (0, (int)getUIPatch (nPatch).NbTilesV-1);
for (int nNewPatch=nFirstPatch; nNewPatch<nFirstPatch+2; nNewPatch++)
{
// Patch ptr
UI_PATCH *pPatch=&getUIPatch (nNewPatch);
// New patch number
int nNewPatchNum=nNewPatch-nFirstPatch;
// Coord of the subpatch
int nV=nNewPatchNum;
// Init patch info without intialize tabl
pPatch->Init (nTileU, nTileV, true);
// Copy info
int nTileCountU=1<<nTileU;
int nTileCountV=1<<nTileV;
int v;
int u;
for(v=0; v<nTileCountV; v++)
for(u=0; u<nTileCountU; u++)
{
// Tile info
int nTile=u+v*nTileCountU;
nlassert (nTile<(int)pPatch->getTileSize());
int nOldTile=u+(nTileCountU*(nV*nTileCountV+v));
nOldTile%=nOldTileCount;
nlassert (nOldTile<(int)getUIPatch (nPatch).getTileSize());
pPatch->getTileDesc (nTile)=getUIPatch (nPatch).getTileDesc (nOldTile);
//pPatch->Tile[nTile].Rotate=getUIPatch (nPatch).Tile[nOldTile].Rotate;
}
for(v=0; v<nTileCountV+1; v++)
for(u=0; u<nTileCountU+1; u++)
{
// Vertex info
int nVertex=u+v*(nTileCountU+1);
nlassert (nVertex<(int)pPatch->getColorSize());
int nOldVertex=u+((nTileCountU+1)*(nV*nTileCountV+v));
nOldVertex%=nOldVertexCount;
nlassert (nOldVertex<(int)getUIPatch (nPatch).getColorSize());
pPatch->setColor (nVertex, getUIPatch (nPatch).getColor (nOldVertex));
}
// Edge info
if (nNewPatch==nFirstPatch)
{
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (0);
pPatch->getEdge (2)=getUIPatch (nPatch).getEdge (2);
pPatch->getEdge (3)=getUIPatch (nPatch).getEdge (3);
}
else
{
pPatch->getEdge (0)=getUIPatch (nPatch).getEdge (0);
pPatch->getEdge (1)=getUIPatch (nPatch).getEdge (1);
pPatch->getEdge (2)=getUIPatch (nPatch).getEdge (2);
}
}
// Update binding info
for (int i=0; i<(int)getUIVertexSize (); i++)
{
if ((getUIVertex (i).Binding.bBinded)&&((int)getUIVertex (i).Binding.nPatch==nPatch))
{
if ((getUIVertex (i).Binding.nEdge&1)==0)
{
UnBindingVertex (i);
}
else
{
if (getUIVertex (i).Binding.nEdge==1)
{
getUIVertex (i).Binding.nPatch=nFirstPatch+1;
getUIVertex (i).Binding.nEdge=1;
}
else
{
nlassert (getUIVertex (i).Binding.nEdge==3);
getUIVertex (i).Binding.nPatch=nFirstPatch;
getUIVertex (i).Binding.nEdge=3;
}
}
}
}
UnbindRelatedPatch (nPatch, patch);
InvalidateBindingInfo ();
}
// return on which edge is
int WhereIsTheEdge (int nPatch, int nEdge, const PatchMesh& patch)
{
for (int i=0; i<4; i++)
{
if ((patch.patches[nPatch].edge[i])==nEdge)
return i;
}
nlassert (0);
return -1;
}
// AddHook
void RPatchMesh::AddHook (int nVert, int nSeg, PatchMesh& patch)
{
#if (MAX_RELEASE < 4000)
// Une side of the edge must be cleared
nlassert (patch.edges[nSeg].patch2==-1);
int patch1 = patch.edges[nSeg].patch1;
#else // (MAX_RELEASE < 4000)
// Une side of the edge must be cleared
nlassert (patch.edges[nSeg].patches.Count()<2);
int patch1 = patch.edges[nSeg].patches.Count()>0?patch.edges[nSeg].patches[0]:-1;
#endif // (MAX_RELEASE < 4000)
int nEdge=WhereIsTheEdge(patch1, nSeg, patch);
nlassert(patch.patches[patch1].edge[nEdge]==nSeg);
BindingVertex(nVert, patch1, nEdge, nVert, BIND_SINGLE);
InvalidateBindingInfo ();
}
// AddHook
void RPatchMesh::AddHook (int nVert0, int nVert1, int nVert2, int nSeg, PatchMesh& patch)
{
#if (MAX_RELEASE < 4000)
// Une side of the edge must be cleared
nlassert (patch.edges[nSeg].patch2==-1);
int patch1 = patch.edges[nSeg].patch1;
#else // (MAX_RELEASE < 4000)
// Une side of the edge must be cleared
nlassert (patch.edges[nSeg].patches.Count()<2);
int patch1 = patch.edges[nSeg].patches.Count()>0?patch.edges[nSeg].patches[0]:-1;
#endif // (MAX_RELEASE < 4000)
int nEdge = WhereIsTheEdge(patch1, nSeg, patch);
BindingVertex(nVert0, patch1, nEdge, nVert1, BIND_25);
BindingVertex(nVert1, patch1, nEdge, nVert1, BIND_50);
BindingVertex(nVert2, patch1, nEdge, nVert1, BIND_75);
InvalidateBindingInfo ();
}
// RemoveHook
void RPatchMesh::RemoveHook (PatchMesh& patch)
{
for (int i=0; i<patch.numVerts; i++)
{
if (patch.vertSel[i])
UnbindRelatedVertex (i, patch);
}
}
// Attach -> binding safe
void RPatchMesh::Attach(RPatchMesh *rattPatch, PatchMesh& patch)
{
// Add to the end.
// Resize buffers
int nOldVertCount=getUIVertexSize();
int nOldPolyCount=getUIPatchSize();
int nNewVertCount=nOldVertCount+rattPatch->getUIVertexSize();
int nNewPolyCount=nOldPolyCount+rattPatch->getUIPatchSize();
SetNumVerts (nNewVertCount);
SetNumPatches (nNewPolyCount);
// Add vert and patch, binding safe
for (int nV=0; nV<nNewVertCount-nOldVertCount; nV++)
{
getUIVertex (nOldVertCount+nV)=rattPatch->getUIVertex (nV);
// Bind patch
if (getUIVertex (nOldVertCount+nV).Binding.bBinded)
{
getUIVertex (nOldVertCount+nV).Binding.nPatch+=nOldPolyCount;
getUIVertex (nOldVertCount+nV).Binding.nPrimVert+=nOldVertCount;
}
}
for (int nP=0; nP<nNewPolyCount-nOldPolyCount; nP++)
getUIPatch (nOldPolyCount+nP)=rattPatch->getUIPatch (nP);
InvalidateBindingInfo ();
}
int GetAdjacent (int nMe, int nedge, PatchMesh *pMesh)
{
int nEdge=pMesh->patches[nMe].edge[nedge];
#if (MAX_RELEASE < 4000)
if (pMesh->edges[nEdge].patch1==nMe)
return pMesh->edges[nEdge].patch2;
else
{
nlassert (pMesh->edges[nEdge].patch2==nMe);
return pMesh->edges[nEdge].patch1;
}
#else // (MAX_RELEASE < 4000)
if ((pMesh->edges[nEdge].patches.Count()>0?pMesh->edges[nEdge].patches[0]:-1)==nMe)
return (pMesh->edges[nEdge].patches.Count()>1?pMesh->edges[nEdge].patches[1]:-1);
else
{
nlassert ((pMesh->edges[nEdge].patches.Count()>1?pMesh->edges[nEdge].patches[1]:-1)==nMe);
return (pMesh->edges[nEdge].patches.Count()>0?pMesh->edges[nEdge].patches[0]:-1);
}
#endif // (MAX_RELEASE < 4000)
}
// return on which edge is
int WhereInMyAdjacent (int nMe, int nAdjacent, PatchMesh *pMesh)
{
for (int i=0; i<4; i++)
{
if (GetAdjacent (nAdjacent, i, pMesh)==nMe)
return i;
}
return -1;
}
// Extrude
void RPatchMesh::CreateExtrusion (PatchMesh *patch)
{
// Resize buffer
int nOldVertCount=getUIVertexSize();
int nOldPolyCount=getUIPatchSize();
int nNewVertCount=patch->getNumVerts ();
int nNewPolyCount=patch->getNumPatches ();
SetNumVerts (nNewVertCount);
SetNumPatches (nNewPolyCount);
patch->buildLinkages();
// update bind data
for (int i=0; i<nOldPolyCount; i++)
{
// Patch selected
if (patch->patchSel[i])
{
/*int nNewFaces[4];
int nWhichEdge[4];
int nEdgeCount=(patch->patches[i].type==PATCH_QUAD)?4:3;
// For all edges
for (int nEdge=0; nEdge<nEdgeCount; nEdge++)
{
// Find the edge
int nE=patch->patches[i].edge[nEdge];
// Find the new face
FindPatch (patch, nE, nWhichEdge[nEdge], nNewFaces[nEdge], nOldPolyCount);
}
// Look for binded point...
for (int nV=0; nV<nOldVertCount; nV++)
{
if (getUIVertex (nV).Binding.bBinded)
{
if ((int)getUIVertex (nV).Binding.nPatch==i)
{
int nEd=getUIVertex (nV).Binding.nEdge;
// Must have been found
nlassert (nNewFaces[nEd]!=-1);
nlassert (nWhichEdge[nEd]!=-1);
UnBindingVertex (i);
getUIVertex (nV).Binding.nPatch=nNewFaces[nEd];
getUIVertex (nV).Binding.nEdge=(nWhichEdge[nEd]+2)&3;
}
}
}*/
// Look for binded point...
for (int nV=0; nV<nOldVertCount; nV++)
{
if (getUIVertex (nV).Binding.bBinded)
{
if ((int)getUIVertex (nV).Binding.nPatch==i)
{
UnbindRelatedVertex (nV, *patch);
}
}
}
}
}
InvalidateBindingInfo ();
// Reinit some patches to get the good UV tessel level
for (int nP=nOldPolyCount; nP<nNewPolyCount; nP++)
{
// Tessel
int nU=RPO_DEFAULT_TESSEL;
int nV=RPO_DEFAULT_TESSEL;
// Look for old adjacent patch
int nAdj=GetAdjacent (nP, 0, patch);
if ((nAdj==-1)||(nAdj>=nOldPolyCount))
nAdj=GetAdjacent (nP, 2, patch);
if ((nAdj!=-1)&&(nAdj<nOldPolyCount))
{
// Where in my adjacent patch
int nInAdj=WhereInMyAdjacent (nP, nAdj, patch);
// Very chelou!
nlassert (nInAdj!=-1);
// Rip U or V?
if (nInAdj&1)
nV=getUIPatch (nAdj).NbTilesU;
else
nV=getUIPatch (nAdj).NbTilesV;
}
// Look for old adjacent patch
nAdj=GetAdjacent (nP, 1, patch);
if ((nAdj==-1)||(nAdj>=nOldPolyCount))
nAdj=GetAdjacent (nP, 3, patch);
if ((nAdj!=-1)&&(nAdj<nOldPolyCount))
{
// Where in my adjacent patch
int nInAdj=WhereInMyAdjacent (nP, nAdj, patch);
// Very chelou!
nlassert (nInAdj!=-1);
// Rip U or V?
if (nInAdj&1)
nU=getUIPatch (nAdj).NbTilesU;
else
nU=getUIPatch (nAdj).NbTilesV;
}
// Reinit?
if ((nU!=RPO_DEFAULT_TESSEL)||(nV!=RPO_DEFAULT_TESSEL))
getUIPatch (nP).Init (nU, nV);
}
}
// Look for a patch with this edge
void RPatchMesh::FindPatch (PatchMesh *patch, int nEdge, int &WhichEdge, int &nPatch, int nFirstPatch)
{
// In the new polygones
int nn;
for (nn=nFirstPatch; nn<patch->numPatches; nn++)
{
int nv;
for (nv=0; nv<4; nv++)
{
if (patch->patches[nn].edge[nv]==nEdge)
{
nPatch=nn;
WhichEdge=nv;
break;
}
}
if (nv!=4)
break;
}
// Not found ?
if (nn==patch->numPatches)
{
nPatch=-1;
WhichEdge=-1;
}
}
// Resolve topologie changes -> Bind safe
void RPatchMesh::ResolveTopoChanges(PatchMesh *patch, bool aux1)
{
// Nombre de patches
if (patch->numPatches>(int)getUIPatchSize())
SetNumPatches (patch->numPatches);
if (patch->numVerts>(int)getUIVertexSize())
SetNumVerts (patch->numVerts);
// static array to avoid alloc prob
static std::vector<UI_PATCH> cUIPatch;
static std::vector<UI_VERTEX> cUIVertex;
static std::vector<int> pnRemapPatch;
static std::vector<int> pnRemapVertex;
// Reserve static array
cUIPatch.reserve (300);
cUIVertex.reserve (300);
pnRemapPatch.reserve (300);
pnRemapVertex.reserve (300);
// Resize arrays
pnRemapPatch.resize (0);
pnRemapPatch.resize (getUIPatchSize(), -1);
pnRemapVertex.resize (0);
pnRemapVertex.resize (getUIVertexSize(), -1);
// Fill the patch array
uint size=getUIPatchSize();
cUIPatch.resize (size);
uint n;
for (n=0; n<size; n++)
cUIPatch[n]=getUIPatch (n);
// Fill the vertex array
size=getUIVertexSize();
cUIVertex.resize (size);
for (n=0; n<size; n++)
cUIVertex[n]=getUIVertex (n);
// Build remap vertex info
int i;
for (i = 0; i < patch->numVerts; ++i)
{
int nTag;
if (aux1)
nTag=patch->verts[i].aux1;
else
nTag=patch->verts[i].aux2;
if (nTag>=0)
{
pnRemapVertex[nTag]=i;
}
}
// Build remap poly info
for (i = 0; i < patch->numPatches; ++i)
{
int nTag;
if (aux1)
nTag=patch->patches[i].aux1;
else
nTag=patch->patches[i].aux2;
if (nTag>=0)
{
pnRemapPatch[nTag]=i;
}
}
// Unbind vertex from deleted vertex
for (i=0; i<(int)pnRemapVertex.size(); i++)
{
if (pnRemapVertex[i]==-1)
{
UnbindRelatedVertex (i, *patch);
}
}
// Unbind vertex from deleted poly
for (i=0; i<(int)pnRemapPatch.size(); i++)
{
if (pnRemapPatch[i]==-1)
{
UnbindRelatedPatch (i, *patch);
}
}
// Remap poly info
for (i = 0; i < patch->numPatches; ++i)
{
int nTag;
if (aux1)
nTag=patch->patches[i].aux1;
else
nTag=patch->patches[i].aux2;
if (nTag>=0)
{
if (nTag!=i)
getUIPatch (i)=cUIPatch[nTag];
}
}
// Remap vertex info
for (i = 0; i < patch->numVerts; ++i)
{
int nTag;
if (aux1)
nTag=patch->verts[i].aux1;
else
nTag=patch->verts[i].aux2;
if ((nTag>=0)&&(nTag!=i))
{
getUIVertex (i)=cUIVertex[nTag];
}
if (getUIVertex (i).Binding.bBinded)
{
int nPatchTag;
nPatchTag=pnRemapPatch[cUIVertex[nTag].Binding.nPatch];
int nVertexTag=pnRemapVertex[cUIVertex[nTag].Binding.nPrimVert];
if ((nPatchTag==-1)||(nVertexTag==-1))
UnBindingVertex (i);
else
{
getUIVertex (i).Binding.nPrimVert=nVertexTag;
getUIVertex (i).Binding.nPatch=nPatchTag;
}
}
}
// Resize buffers
SetNumPatches (patch->numPatches);
SetNumVerts (patch->numVerts);
// Invalidate binding infos
InvalidateBindingInfo ();
}
// Weld -> Bind safe
void RPatchMesh::Weld (PatchMesh *patch)
{
ResolveTopoChanges(patch, false);
}
int GetEdgeNumberInPatch (int nPatch, int nEdge, PatchMesh *patch)
{
for (int i=0; i<4; i++)
{
if (patch->patches[nPatch].edge[i]==nEdge)
return i;
}
return -1;
}
// Add a patch
void RPatchMesh::AddPatch (int nEdge, int nFirstPatch, PatchMesh *patch)
{
// Add a patch
SetNumPatches (getUIPatchSize()+1);
// Find the tile resolution...
int nV=RPO_DEFAULT_TESSEL;
int nedge=GetEdgeNumberInPatch (nFirstPatch, nEdge, patch);
nlassert (nedge!=-1);
if (nedge&1)
nV=getUIPatch (nFirstPatch).NbTilesU;
else
nV=getUIPatch (nFirstPatch).NbTilesV;
getUIPatch (getUIPatchSize()-1).Init (nV, nV);
}
// Unbind vertex associed to the vertex
void RPatchMesh::UnbindRelatedVertex (int nVertex, PatchMesh& patch)
{
uint nFace=getUIVertex (nVertex).Binding.nPatch;
uint nEdge=getUIVertex (nVertex).Binding.nEdge;
for (int j=0; j<(int)getUIVertexSize(); j++)
{
if ((getUIVertex (j).Binding.bBinded)&&
(getUIVertex (j).Binding.nPatch==nFace)&&
(getUIVertex (j).Binding.nEdge==nEdge))
{
UnBindingVertex (j);
}
}
}
// Unbind vertex associed to the patch
void RPatchMesh::UnbindRelatedPatch (int nPatch, PatchMesh& patch)
{
for (int i=0; i<4; i++)
{
int n=patch.patches[nPatch].v[i];
if (getUIVertex (n).Binding.bBinded)
{
UnbindRelatedVertex (n, patch);
}
}
}
// Delete patches and vertices
void RPatchMesh::DeleteAndSweep (const BitArray &remapVerts, const BitArray &remapPatches, PatchMesh& patch)
{
int mapVSize=remapVerts.GetSize();
int vSize=getUIVertexSize();
int mapPSize=remapPatches.GetSize();
int pSize=getUIPatchSize();
nlassert (mapVSize==vSize);
nlassert (mapPSize==pSize);
int i,j;
// Unbind vertex from deleted vertex
for (i=0; i<(int)getUIVertexSize(); i++)
{
if (remapVerts[i])
{
UnbindRelatedVertex (i, patch);
}
}
// Unbind vertex from deleted poly
for (i=0; i<(int)getUIPatchSize(); i++)
{
if (remapPatches[i])
{
UnbindRelatedPatch (i, patch);
}
}
// Make vertex remap table
static std::vector<int> newVIndex;
newVIndex.reserve (1000);
newVIndex.resize (vSize);
for (i=0, j=0; i<vSize; i++)
{
if (i!=j)
getUIVertex (j)=getUIVertex (i);
if (remapVerts[i])
newVIndex[i]=-1;
else
newVIndex[i]=j++;
}
SetNumVerts (j);
//UIVertex.resize (j);
// Make patch remap table
static std::vector<int> newPIndex;
newPIndex.reserve (1000);
newPIndex.resize (pSize);
for (i=0, j=0; i<pSize; i++)
{
if (i!=j)
getUIPatch (j)=getUIPatch (i);
if (remapPatches[i])
newPIndex[i]=-1;
else
newPIndex[i]=j++;
}
SetNumPatches (j);
//getUIPatch )resize (j);
// Remap bind
for (i=0; i<(int)getUIVertexSize(); i++)
{
if (getUIVertex (i).Binding.bBinded)
{
int nPrim=newVIndex[getUIVertex (i).Binding.nPrimVert];
int nPatch=newPIndex[getUIVertex (i).Binding.nPatch];
if ((nPatch==-1)||(nPrim==-1))
UnBindingVertex (i);
else
{
getUIVertex (i).Binding.nPrimVert=nPrim;
getUIVertex (i).Binding.nPatch=nPatch;
}
}
}
InvalidateBindingInfo ();
}
// Invalidate channels
void RPatchMesh::InvalidateChannels(ChannelMask channels)
{
if (channels&TOPO_CHANNEL)
{
ValidTopo=NEVER;
//InvalidateBindingInfo ();
}
if (channels&GEOM_CHANNEL)
{
ValidGeom=NEVER;
//InvalidateBindingPos ();
}
if (channels&SELECT_CHANNEL)
ValidSelect=NEVER;
if (channels&TEXMAP_CHANNEL)
ValidTexmap=NEVER;
if (channels&DISP_ATTRIB_CHANNEL)
ValidDisplay=NEVER;
}
// Load
IOResult RPatchMesh::Load(ILoad *iload)
{
ULONG nb;
// Version
unsigned int nVersion;
iload->Read(&nVersion, sizeof (nVersion), &nb);
switch (nVersion)
{
case RPATCHMESH_SERIALIZE_VERSION_9:
case RPATCHMESH_SERIALIZE_VERSION_8:
case RPATCHMESH_SERIALIZE_VERSION_7:
case RPATCHMESH_SERIALIZE_VERSION_6:
case RPATCHMESH_SERIALIZE_VERSION_5:
case RPATCHMESH_SERIALIZE_VERSION_4:
case RPATCHMESH_SERIALIZE_VERSION_3:
case RPATCHMESH_SERIALIZE_VERSION_2:
case RPATCHMESH_SERIALIZE_VERSION_1:
{
// Patch info
int nSize;
iload->Read(&nSize, sizeof (nSize), &nb);
SetNumPatches (nSize);
int i;
for (i=0; i<nSize; i++)
{
iload->Read(&getUIPatch (i).NbTilesU, sizeof (int), &nb);
iload->Read(&getUIPatch (i).NbTilesV, sizeof (int), &nb);
if (nVersion<RPATCHMESH_SERIALIZE_VERSION_3)
{
// Tiles
int nSize2;
iload->Read(&nSize2, sizeof (int), &nb);
for (int j=0; j<nSize2; j++)
{
int old;
iload->Read(&old, sizeof (int), &nb);
iload->Read(&old, sizeof (int), &nb);
getUIPatch (i).getTileDesc (j).setEmpty ();
}
}
else // RPATCHMESH_SERIALIZE_VERSION_3
{
// Tiles
int nSize2;
iload->Read(&nSize2, sizeof (int), &nb);
for (int j=0; j<nSize2; j++)
{
iload->Read(&getUIPatch (i).getTileDesc (j)._Num, sizeof (USHORT), &nb);
// Version 5, number of cell for 256x256 tiles
if (nVersion>=RPATCHMESH_SERIALIZE_VERSION_5)
iload->Read(&getUIPatch (i).getTileDesc (j)._Flags, sizeof (USHORT), &nb);
else
getUIPatch (i).getTileDesc (j)._Flags=0;
// Clear displace flags in version lower than 8
if (nVersion<RPATCHMESH_SERIALIZE_VERSION_9)
{
// Random a noise tile between 0 and 7
uint noise=rand ()&0x7;
getUIPatch (i).getTileDesc (j).setDisplace (noise);
}
else
{
// Read the noise
uint8 noise;
iload->Read(&noise, sizeof (uint8), &nb);
getUIPatch (i).getTileDesc (j).setDisplace (noise);
}
for (int k=0; k<3; k++)
{
bool invert;
int tile;
int rotate;
iload->Read(&invert, sizeof (bool), &nb);
iload->Read(&tile, sizeof (int), &nb);
iload->Read(&rotate, sizeof (int), &nb);
// Not used anymore getUIPatch (i).getTileDesc (j)._MatIDTab[k].Invert=invert;
getUIPatch (i).getTileDesc (j)._MatIDTab[k].Tile=tile;
getUIPatch (i).getTileDesc (j)._MatIDTab[k].Rotate=rotate;
}
}
}
// Colors
int nSize2;
iload->Read(&nSize2, sizeof (int), &nb);
for (int j=0; j<nSize2; j++)
{
uint color;
iload->Read(&color, sizeof (uint), &nb);
getUIPatch (i).setColor (j, color);
// Before RPATCHMESH_SERIALIZE_VERSION_6, force color to white
if (nVersion<RPATCHMESH_SERIALIZE_VERSION_6)
getUIPatch (i).setColor (j, 0xffffff);
}
// Edges info
if (nVersion>=RPATCHMESH_SERIALIZE_VERSION_7)
{
// Save the 4 edges
for (int e=0; e<4; e++)
{
// Get an edge ref
CEdgeInfo& edge=getUIPatch (i).getEdge (e);
// Read it
iload->Read(&edge.Flags, sizeof (uint32), &nb);
}
}
}
// Vertex info
iload->Read(&nSize, sizeof (nSize), &nb);
SetNumVerts (nSize);
for (i=0; i<nSize; i++)
{
bool bBinded;
typeBind nType;
uint nEdge;
uint nPatch;
uint nBefore;
uint nBefore2;
uint nAfter;
uint nAfter2;
uint nT;
uint nPrimVert;
iload->Read(&bBinded, sizeof (bool), &nb);
iload->Read(&nType, sizeof (typeBind), &nb);
iload->Read(&nEdge, sizeof (uint), &nb);
iload->Read(&nPatch, sizeof (uint), &nb);
iload->Read(&nBefore, sizeof (uint), &nb);
iload->Read(&nBefore2, sizeof (uint), &nb);
iload->Read(&nAfter, sizeof (uint), &nb);
iload->Read(&nAfter2, sizeof (uint), &nb);
iload->Read(&nT, sizeof (uint), &nb);
iload->Read(&nType, sizeof (typeBind), &nb);
iload->Read(&nPrimVert, sizeof (uint), &nb);
getUIVertex (i).Binding.bBinded=bBinded;
getUIVertex (i).Binding.nType=nType;
getUIVertex (i).Binding.nEdge=nEdge;
getUIVertex (i).Binding.nPatch=nPatch;
getUIVertex (i).Binding.nBefore=nBefore;
getUIVertex (i).Binding.nBefore2=nBefore2;
getUIVertex (i).Binding.nAfter=nAfter;
getUIVertex (i).Binding.nAfter2=nAfter2;
getUIVertex (i).Binding.nT=nT;
getUIVertex (i).Binding.nType=nType;
getUIVertex (i).Binding.nPrimVert=nPrimVert;
}
// Some info
iload->Read(&rTess.TileTesselLevel, sizeof (rTess.TileTesselLevel), &nb);
iload->Read(&rTess.ModeTile, sizeof (rTess.ModeTile), &nb);
iload->Read(&rTess.KeepMapping, sizeof (rTess.KeepMapping), &nb);
if (nVersion==RPATCHMESH_SERIALIZE_VERSION_4)
iload->Read(&rTess.TransitionType, sizeof (rTess.TransitionType), &nb);
iload->Read(&selLevel, sizeof (selLevel), &nb);
}
break;
default:
return IO_ERROR;
}
ValidGeom.SetEmpty();
ValidTopo.SetEmpty();
ValidTexmap.SetEmpty();
ValidSelect.SetEmpty();
ValidDisplay.SetEmpty();
ValidBindingInfo.SetEmpty();
ValidBindingPos.SetEmpty();
return IO_OK;
}
// Save
IOResult RPatchMesh::Save(ISave *isave)
{
ULONG nb;
// Version
unsigned int nVersion=RPATCHMESH_SERIALIZE_VERSION;
isave->Write(&nVersion, sizeof (nVersion), &nb);
// Patch info
int nSize=getUIPatchSize();
isave->Write(&nSize, sizeof (nSize), &nb);
int i;
for (int i=0; i<nSize; i++)
{
isave->Write(&getUIPatch (i).NbTilesU, sizeof (int), &nb);
isave->Write(&getUIPatch (i).NbTilesV, sizeof (int), &nb);
// Tiles
int nSize2=getUIPatch (i).getTileSize();
isave->Write(&nSize2, sizeof (int), &nb);
int j;
for (j=0; j<nSize2; j++)
{
USHORT num=getUIPatch (i).getTileDesc (j)._Num;
isave->Write(&num, sizeof (USHORT), &nb);
num=getUIPatch (i).getTileDesc (j)._Flags;
isave->Write(&num, sizeof (USHORT), &nb);
// Save noise
uint8 noise=getUIPatch (i).getTileDesc (j).getDisplace ();
isave->Write(&noise, sizeof (uint8), &nb);
for (int k=0; k<3; k++)
{
bool invert = false;
int tile;
int rotate;
// Not used anymore invert=(getUIPatch (i).getTileDesc (j)._MatIDTab[k].Invert!=0);
tile=getUIPatch (i).getTileDesc (j)._MatIDTab[k].Tile;
rotate=getUIPatch (i).getTileDesc (j)._MatIDTab[k].Rotate;
isave->Write(&invert, sizeof (bool), &nb);
isave->Write(&tile, sizeof (int), &nb);
isave->Write(&rotate, sizeof (int), &nb);
}
}
// Colors
nSize2=getUIPatch (i).getColorSize();
isave->Write(&nSize2, sizeof (int), &nb);
for (j=0; j<nSize2; j++)
{
uint color=getUIPatch (i).getColor (j);
isave->Write(&color, sizeof (int), &nb);
}
// Edges info (nVersion >= RPATCHMESH_SERIALIZE_VERSION_7)
// Save the 4 edges
for (int e=0; e<4; e++)
{
// Get an edge ref
const CEdgeInfo& edge=getUIPatch (i).getEdge (e);
// Write it
isave->Write(&edge.Flags, sizeof (uint32), &nb);
}
}
// Vertex info
nSize=getUIVertexSize();
isave->Write(&nSize, sizeof (nSize), &nb);
for (i=0; i<nSize; i++)
{
bool bBinded=(getUIVertex (i).Binding.bBinded!=0);
uint nEdge=getUIVertex (i).Binding.nEdge;
uint nPatch=getUIVertex (i).Binding.nPatch;
uint nBefore=getUIVertex (i).Binding.nBefore;
uint nBefore2=getUIVertex (i).Binding.nBefore2;
uint nAfter=getUIVertex (i).Binding.nAfter;
uint nAfter2=getUIVertex (i).Binding.nAfter2;
uint nT=getUIVertex (i).Binding.nT;
typeBind nType=(typeBind)getUIVertex (i).Binding.nType;
uint nPrimVert=getUIVertex (i).Binding.nPrimVert;
isave->Write(&bBinded, sizeof (bool), &nb);
isave->Write(&nType, sizeof (typeBind), &nb);
isave->Write(&nEdge, sizeof (uint), &nb);
isave->Write(&nPatch, sizeof (uint), &nb);
isave->Write(&nBefore, sizeof (uint), &nb);
isave->Write(&nBefore2, sizeof (uint), &nb);
isave->Write(&nAfter, sizeof (uint), &nb);
isave->Write(&nAfter2, sizeof (uint), &nb);
isave->Write(&nT, sizeof (uint), &nb);
isave->Write(&nType, sizeof (typeBind), &nb);
isave->Write(&nPrimVert, sizeof (uint), &nb);
}
// Some info
isave->Write(&rTess.TileTesselLevel, sizeof (rTess.TileTesselLevel), &nb);
isave->Write(&rTess.ModeTile, sizeof (rTess.ModeTile), &nb);
isave->Write(&rTess.KeepMapping, sizeof (rTess.KeepMapping), &nb);
isave->Write(&rTess.TransitionType, sizeof (rTess.TransitionType), &nb);
isave->Write(&selLevel, sizeof (selLevel), &nb);
return IO_OK;
};
// *** Tile Methods
// Get the matrix of the selected tiles
Matrix3 RPatchMesh::GetSelTileTm(PatchMesh& patch, TimeValue t, INode *node, bool& bHasSel) const
{
Interval valid;
Box3 box;
Matrix3 otm = node->GetObjectTM(t, &valid);
Matrix3 tm = node->GetNodeTM(t, &valid);
bHasSel = false;
// For all patchs
for (int nPatch=0; nPatch<(int)getUIPatchSize(); nPatch++)
{
float fV=0;
int nBU=1<<getUIPatch (nPatch).NbTilesU;
int nBV=1<<getUIPatch (nPatch).NbTilesV;
float fDU=1.f/(float)nBU;
float fDV=1.f/(float)nBV;
for (int nV=0; nV<nBV; nV++)
{
float fU=0;
for (int nU=0; nU<nBU; nU++)
{
int nTileNumber=GetTileNumber(nPatch, nU, nV);
if (tileSel[nTileNumber])
{
bHasSel = true;
box += patch.patches[nPatch].interp (&patch, fU, fV);
box += patch.patches[nPatch].interp (&patch, fU+fDU, fV);
box += patch.patches[nPatch].interp (&patch, fU+fDU, fV+fDV);
box += patch.patches[nPatch].interp (&patch, fU, fV+fDV);
}
fU += fDU;
}
fV += fDV;
}
}
tm.SetTrans(otm * box.Center());
return tm;
}
// Get the center of the selected tiles
Point3 RPatchMesh::GetSelTileCenter(PatchMesh& patch, TimeValue t, INode *node, bool& bHasSel) const
{
Interval valid;
Box3 box;
Matrix3 tm = node->GetObjectTM(t, &valid);
bHasSel=false;
// For all patchs
for (int nPatch=0; nPatch<(int)getUIPatchSize(); nPatch++)
{
float fV=0;
int nBU=1<<getUIPatch (nPatch).NbTilesU;
int nBV=1<<getUIPatch (nPatch).NbTilesV;
float fDU=1.f/(float)nBU;
float fDV=1.f/(float)nBV;
for (int nV=0; nV<nBV; nV++)
{
float fU=0;
for (int nU=0; nU<nBU; nU++)
{
int nTileNumber=GetTileNumber(nPatch, nU, nV);
if (tileSel[nTileNumber])
{
bHasSel=true;
box += patch.patches[nPatch].interp (&patch, fU, fV) * tm;
box += patch.patches[nPatch].interp (&patch, fU+fDU, fV) * tm;
box += patch.patches[nPatch].interp (&patch, fU+fDU, fV+fDV) * tm;
box += patch.patches[nPatch].interp (&patch, fU, fV+fDV) * tm;
}
fU += fDU;
}
fV += fDV;
}
}
return box.Center();
}
// Hittest method
BOOL RPatchMesh::SubObjectHitTest (GraphicsWindow *gw, Material *ma, HitRegion *hr, DWORD flags, SubPatchHitList& hitList,
TimeValue t, PatchMesh& patch)
{
// Return value
BOOL bRet=FALSE;
// Build the mesh
BuildMesh (t, patch);
if (rTess.TileTesselLevel>=0)
{
nlassert (mesh.numFaces==(int)getMapHitSize ());
for (int nf=0; nf<mesh.numFaces; nf++)
{
if (mesh.faceSel[nf])
int toto=0;
}
// Hittest the mesh
int nFlags=SUBHIT_FACES;
if (flags&SUBHIT_PATCH_SELONLY)
{
nFlags|=SUBHIT_SELONLY;
}
if (flags&SUBHIT_PATCH_UNSELONLY)
nFlags|=SUBHIT_UNSELONLY;
if (flags&SUBHIT_PATCH_ABORTONHIT)
nFlags|=SUBHIT_ABORTONHIT;
if (flags&SUBHIT_PATCH_SELSOLID)
nFlags|=SUBHIT_SELSOLID;
// Mesh flags
mesh.SetDispFlag (DISP_SELFACES);
mesh.selLevel = MESH_FACE;
// Hittest
SubObjHitList list;
gw->setRndLimits(gw->getRndLimits() & ~GW_BACKCULL);
bRet=mesh.SubObjectHitTest (gw, ma, hr, nFlags, list);
MeshSubHitRec *rec=list.First();
while (rec)
{
if (flags&SUBHIT_PATCH_SELONLY)
{
int otot=0;
}
if (flags&SUBHIT_PATCH_UNSELONLY)
{
int otot=0;
}
// Check the hit
nlassert (rec->index>=0);
nlassert (rec->index<(int)getMapHitSize ());
nlassert (rec->index<mesh.numFaces);
// Remap the index
int nRemapedIndex=remapTriangle (rec->index);
// Add a patch hit
hitList.AddHit (rec->dist, &patch, nRemapedIndex, PATCH_HIT_TILE);
// Next hit
rec=rec->Next();
}
}
return bRet;
}
// Return the patch adjacent at nPatch in the edge nEdge. If no patch adjacent, return nPatch
int GetAdjacentPatch (int nPatch, int nEdge, PatchMesh *patch)
{
PatchEdge *pEdge=patch->edges+patch->patches[nPatch].edge[nEdge];
#if (MAX_RELEASE < 4000)
nlassert ((pEdge->patch1==nPatch)||(pEdge->patch2==nPatch));
if (pEdge->patch1==nPatch)
return (pEdge->patch2!=-1)?pEdge->patch2:nPatch;
else
return (pEdge->patch1!=-1)?pEdge->patch1:nPatch;
#else // (MAX_RELEASE < 4000)
nlassert ((pEdge->patches.Count()>0&&pEdge->patches[0]==nPatch)||(pEdge->patches.Count()>1&&pEdge->patches[1]==nPatch));
if (pEdge->patches[0]==nPatch)
return (pEdge->patches.Count()>1&&pEdge->patches[1]!=-1)?pEdge->patches[1]:nPatch;
else
return (pEdge->patches.Count()>0&&pEdge->patches[0]!=-1)?pEdge->patches[0]:nPatch;
#endif // (MAX_RELEASE < 4000)
}
// Build the mesh
void RPatchMesh::BuildMesh(TimeValue t, PatchMesh& patch, Mesh *pMesh)
{
// Check validity
Point3 point;
int x,y;
// Mesh pointer
if (!pMesh)
pMesh=&mesh;
// Chech binding info are valid
UpdateBinding (patch, t);
nlassert (ValidBindingPos.InInterval (t));
nlassert (ValidBindingInfo.InInterval (t));
ChannelMask Build=0;
if (!ValidTopo.InInterval (t))
{
Build|=PART_TOPO;
}
if (!ValidGeom.InInterval (t))
{
Build|=PART_GEOM;
}
if (!ValidTexmap.InInterval (t))
{
Build|=PART_TEXMAP;
}
if (!ValidSelect.InInterval (t))
{
Build|=PART_SELECT|PART_TOPO|PART_GEOM;
}
if (!ValidDisplay.InInterval (t))
{
Build|=PART_DISPLAY;
}
if (!Build)
return;
TTicks ticks=CTime::getPerformanceTime ();
#ifndef NDEBUG
Validity (patch, true);
#endif // NDEBUG
// Build tracking
static int nBuildNumber=0;
build=nBuildNumber++;
// Textured mode ?
bool bTextured=false;
if (rTess.TileTesselLevel>=0)
// ok, there is at least two tri for a tile, so we can texture...
bTextured=true;
// Count channels
int nChannelCount=0;
BitArray pChannelBit (MAX_MESHMAPS);
pChannelBit.ClearAll ();
int nChannel;
for (nChannel=0; nChannel<MAX_MESHMAPS; nChannel++)
{
if ((patch.getNumMapVerts(nChannel)>0)||((!rTess.KeepMapping)&&(nChannel==1)))
{
pChannelBit.Set (nChannel);
nChannelCount=nChannel+1;
}
}
// Show interior ?
bool bShowInter=(patch.GetShowInterior()!=0);
if (Build&(PART_TOPO|PART_GEOM))
{
int nbdivsU,nbdivsV;
int nf=0;
int finalVertexCount=0;
for(int p=0 ; p<patch.getNumPatches() ; p++)
{
if (patch.patches[p].type==PATCH_QUAD)
{
// Quads count in U and V
GetPatchTess (p, nbdivsU, nbdivsV);
// Quads count in U and V
nf+=2*nbdivsU*nbdivsV;
finalVertexCount+=(nbdivsV+1)*(nbdivsU+1);
}
}
// Setup count
if (Build|=PART_GEOM)
{
pMesh->setNumVerts(finalVertexCount,FALSE,TRUE);
// Rebuild bind info
//UpdateBindingInfo (patch);
}
if (Build|=PART_TOPO)
{
// Num of patch
pMesh->setNumFaces(nf,FALSE,TRUE);
if (bTextured)
resizeMapHit (nf);
// For each channel
for (nChannel=0; nChannel<nChannelCount; nChannel++)
{
if (pChannelBit[nChannel])
{
// Activate this channel (mandatory for Max 4.2)
pMesh->setMapSupport(nChannel, TRUE);
if (rTess.KeepMapping||!bTextured||(nChannel!=1))
{
// Number of vertex
pMesh->setNumMapVerts (nChannel, finalVertexCount);
}
else
{
// Number of vertex
pMesh->setNumMapVerts (nChannel, (nf/2)*4);
}
// Num of patch
pMesh->setNumMapFaces(nChannel, nf);
}
}
}
}
if (Build&(PART_GEOM|PART_GEOM|PART_SELECT|PART_TEXMAP))
{
// First vertex of the two tri...
int offset=0;
// Next face index
int f=0;
// Next vertex index
int nv=0;
// Next mapping vertex index
int mp=0;
// First Edge
int ne=0;
// Clear the edges
if (Build&PART_SELECT)
pMesh->edgeSel.ClearAll ();
// Tile level
int nTileLevel=rTess.TileTesselLevel;
// Count of vertex by tile
int nVertexTileCount=(1<<nTileLevel)*2;
// Corner coord
Point3 vTt[4][5]=
{
{ Point3 (0,1,0), Point3 (0,1,0), Point3 (0.f,0.5f,0.f), Point3 (0.5f,0.5f,0.f), Point3 (0.5f,1.f,0.f) },
{ Point3 (0,0,0), Point3 (0.f,0.5f,0.f), Point3 (0,0,0), Point3 (0.5f,0.f,0.f), Point3 (0.5f,0.5f,0.f) },
{ Point3 (1,0,0), Point3 (0.5f,0.5f,0.f), Point3 (0.5f,0.f,0.f), Point3 (1.f,0.f,0.f), Point3 (1.f,0.5f,0.f) },
{ Point3 (1,1,0), Point3 (0.5f,1.f,0.f), Point3 (0.5f,0.5f,0.f), Point3 (1.f,0.5f,0.f), Point3 (1.f,1.f,0.f) }
};
for(int p=0 ; p<patch.getNumPatches() ; p++)
{
// Check it's a quad patch
if (patch.patches[p].type==PATCH_QUAD)
{
int nbdivsU, nbdivsV;
// Tessel in U and V
GetPatchTess (p, nbdivsU, nbdivsV);
// Delta for mapping
float fUd=1.f/(float)nbdivsU;
float fVd=1.f/(float)nbdivsV;
// Delta for mapping
float fTiled=1.f/(float)(1<<nTileLevel);
// Count of vertex in the patch
int nUCount=nbdivsU+1;
int nVCount=nbdivsV+1;
// Number of tile
int nTileCountU=1<<getUIPatch (p).NbTilesU;
int nTileCountV=1<<getUIPatch (p).NbTilesV;
// Nb face in a tile
int nTess=1<<rTess.TileTesselLevel;
// Vertices have changed
if (Build&(PART_GEOM|PART_SELECT))
{
int nV;
if (Build&PART_GEOM)
{
float oonbdivsU=1.0f/(float)nbdivsU;
float oonbdivsV=1.0f/(float)nbdivsV;
// Compute the vertices
for(nV=0 ; nV<=nbdivsV; ++nV)
{
float v=(float)nV*oonbdivsV;
for(int nU=0 ; nU<=nbdivsU ; nU++)
{
float u=(float)nU*oonbdivsU;
point=patch.patches[p].interp(&patch,u,v);
pMesh->setVert(nv, point);
nv++;
}
}
}
// Vertices selection
if (Build&PART_SELECT)
{
pMesh->vertSel.Set ( offset, patch.vertSel[patch.patches[p].v[0]]);
pMesh->vertSel.Set ( offset+nbdivsV*(nbdivsU+1), patch.vertSel[patch.patches[p].v[1]]);
pMesh->vertSel.Set ( offset+nbdivsV*(nbdivsU+1)+nbdivsU, patch.vertSel[patch.patches[p].v[2]]);
pMesh->vertSel.Set ( offset+nbdivsU, patch.vertSel[patch.patches[p].v[3]]);
}
}
if (Build&(PART_TOPO|PART_SELECT|PART_TEXMAP))
{
if (Build&PART_SELECT)
{
// Hide all verts
int nLastVert=offset+(nbdivsV+1)*(nbdivsU+1);
for (int tt=offset; tt<nLastVert; tt++)
{
pMesh->vertHide.Set (tt);
}
// Show some of them
pMesh->vertHide.Clear (offset);
pMesh->vertHide.Clear (offset+nbdivsU);
pMesh->vertHide.Clear (nLastVert-1-nbdivsU);
pMesh->vertHide.Clear (nLastVert-1);
// Edge selection
int ne=f*3;
if (GetSelLevel()==EP_PATCH)
{
int bPatchSel=patch.patchSel[p];
int nUV=nbdivsU*nbdivsV;
if (bPatchSel||patch.patchSel[GetAdjacentPatch (p, 3, &patch)])
{
// Top
for (int ee=0; ee<nbdivsU; ee++)
pMesh->edgeSel.Set (ne+6*ee+2);
}
if (bPatchSel||patch.patchSel[GetAdjacentPatch (p, 1, &patch)])
{
// Bottom
for (int ee=nUV-nbdivsU; ee<nUV; ee++)
pMesh->edgeSel.Set (ne+6*ee+3);
}
if (bPatchSel||patch.patchSel[GetAdjacentPatch (p, 0, &patch)])
{
// Left
for (int ee=0; ee<nbdivsV; ee++)
pMesh->edgeSel.Set (ne+6*nbdivsU*ee);
}
if (bPatchSel||patch.patchSel[GetAdjacentPatch (p, 2, &patch)])
{
// Right
for (int ee=0; ee<nbdivsV; ee++)
pMesh->edgeSel.Set (ne+6*nbdivsU*ee+4+6*(nbdivsU-1));
}
}
else if ((GetSelLevel()==EP_EDGE)||paint)
{
// Top
if (patch.edgeSel[patch.patches[p].edge[3]])
{
for (int ee=0; ee<nbdivsU; ee++)
pMesh->edgeSel.Set(ne+6*ee+2);
}
// Bottom
if (patch.edgeSel[patch.patches[p].edge[1]])
{
int nUV=nbdivsU*nbdivsV;
for (int ee=nUV-nbdivsU; ee<nUV; ee++)
pMesh->edgeSel.Set(ne+6*ee+3);
}
// Left
if (patch.edgeSel[patch.patches[p].edge[0]])
{
for (int ee=0; ee<nbdivsV; ee++)
pMesh->edgeSel.Set(ne+6*nbdivsU*ee);
}
// Right
if (patch.edgeSel[patch.patches[p].edge[2]])
{
for (int ee=0; ee<nbdivsV; ee++)
pMesh->edgeSel.Set(ne+6*nbdivsU*ee+4+6*(nbdivsU-1));
}
}
}
// Topology has changed
int mpcopy=mp;
int offsetcopy=offset;
for(y=0 ; y<nbdivsV ; y++)
{
for(x=0 ; x<nbdivsU ; x++)
{
if (Build&(PART_TOPO|PART_SELECT))
{
pMesh->faces[f].v[0]=offset+x;
pMesh->faces[f].v[1]=offset+x+(nbdivsU+1);
pMesh->faces[f].v[2]=offset+x+1;
pMesh->faces[f].flags&=~(EDGE_ALL);
if (bShowInter)
pMesh->faces[f].flags|=EDGE_A|EDGE_C;
if (x==0)
pMesh->faces[f].flags|=EDGE_A;
if (y==0)
pMesh->faces[f].flags|=EDGE_C;
pMesh->faces[f].smGroup=1;
pMesh->faces[f+1].v[0]=offset+x+(nbdivsU+1);
pMesh->faces[f+1].v[1]=offset+x+(nbdivsU+1)+1;
pMesh->faces[f+1].v[2]=offset+x+1;
pMesh->faces[f+1].flags&=~(EDGE_ALL);
if (bShowInter)
pMesh->faces[f+1].flags|=EDGE_A|EDGE_B;
if (x==nbdivsU-1)
pMesh->faces[f+1].flags|=EDGE_B;
if (y==nbdivsV-1)
pMesh->faces[f+1].flags|=EDGE_A;
pMesh->faces[f+1].smGroup=1;
// MatId
/*pMesh->faces[f].setMatID((abs(f>>1)%3));
pMesh->faces[f+1].setMatID((abs(f>>1)%3));*/
// Tile number
// Face display
if (patch.patches[p].flags&PATCH_HIDDEN)
{
pMesh->faces[f].flags|=FACE_HIDDEN;
pMesh->faces[f+1].flags|=FACE_HIDDEN;
}
else
{
pMesh->faces[f].flags&=~(FACE_HIDDEN);
pMesh->faces[f+1].flags&=~(FACE_HIDDEN);
}
// Texture maps
int nTileU=x>>nTileLevel;
int nTileV=y>>nTileLevel;
for (nChannel=0; nChannel<nChannelCount; nChannel++)
{
if (pChannelBit[nChannel])
{
TVFace *pTvP=pMesh->mapFaces(nChannel);
nlassert (pTvP);
if (pTvP)
{
pTvP+=f;
if (rTess.KeepMapping||!bTextured||(nChannel!=1))
{
pTvP->t[0]=offset+x;
pTvP->t[1]=offset+x+(nbdivsU+1);
pTvP->t[2]=offset+x+1;
pTvP++;
pTvP->t[0]=offset+x+(nbdivsU+1);
pTvP->t[1]=offset+x+(nbdivsU+1)+1;
pTvP->t[2]=offset+x+1;
}
else
{
int nX2=x*2;
pTvP->t[0]=mp+nX2;
pTvP->t[1]=mp+nX2+nbdivsU*2;
pTvP->t[2]=mp+nX2+1;
pTvP++;
pTvP->t[0]=mp+nX2+nbdivsU*2;
pTvP->t[1]=mp+nX2+nbdivsU*2+1;
pTvP->t[2]=mp+nX2+1;
}
}
}
}
}
if (Build&PART_TEXMAP)
{
int uTile=x>>nTileLevel;
int vTile=y>>nTileLevel;
uint nTileNumber=0;
tileDesc& desc=getUIPatch (p).getTileDesc (uTile+vTile*nTileCountU);
if (!desc.isEmpty ())
{
nTileNumber=desc.getLayer(std::min (desc.getNumLayer()-1, rTess.TransitionType-1)).Tile+1;
}
pMesh->faces[f].setMatID(nTileNumber);
pMesh->faces[f+1].setMatID(nTileNumber);
}
if (Build&PART_SELECT)
{
// Remap for hittest
if (bTextured)
{
int nU=x>>rTess.TileTesselLevel;
int nV=y>>rTess.TileTesselLevel;
int tileNumber=GetTileNumber(p, nU, nV);
setRemapEntry (f, tileNumber);
setRemapEntry (f+1, tileNumber);
if (GetSelLevel()==EP_TILE)
{
int bTileSel=tileSel[tileNumber];
if (bTileSel)
{
// Top
if ((y&(nTess-1))==0)
pMesh->edgeSel.Set(3*f+2);
// Left
if ((x&(nTess-1))==0)
pMesh->edgeSel.Set(3*f);
// Bottom
if ((y&(nTess-1))==(nTess-1))
pMesh->edgeSel.Set(3*f+3);
// Right
if ((x&(nTess-1))==(nTess-1))
pMesh->edgeSel.Set(3*f+4);
}
// Face selection
pMesh->faceSel.Set (f, bTileSel);
pMesh->faceSel.Set (f+1, bTileSel);
}
}
}
f+=2;
}
offset+=nbdivsU+1;
mp+=nbdivsU*4;
}
offset+=nbdivsU+1;
// Generate texture vertices
if ((Build&PART_TOPO)|(Build&PART_TEXMAP))
{
// Copy mapping
// For each channel
for (nChannel=0; nChannel<nChannelCount; nChannel++)
{
if (pChannelBit[nChannel])
{
if (rTess.KeepMapping||!bTextured||(nChannel!=1))
{
Point3 vT[4];
if (rTess.KeepMapping||(nChannel!=1))
{
for (int ii=0; ii<4; ii++)
vT[ii]=patch.getMapVert (nChannel, patch.tvPatches[nChannel][p].tv[ii]);
}
else
{
for (int ii=0; ii<4; ii++)
vT[ii]=Point3 (0,0,0);
}
// For each vertex
float fV=0.f;
for (int v=0; v<nVCount; v++)
{
float fU=0.f;
for (int u=0; u<nUCount; u++)
{
Point3 vRight=(vT[(2)&3]-vT[(3)&3])*fV+vT[(3)&3];
Point3 vLeft=(vT[(1)&3]-vT[(0)&3])*fV+vT[(0)&3];
Point3 vPoint=(vRight-vLeft)*fU+vLeft;
pMesh->setMapVert (nChannel, offsetcopy+u+v*nUCount, vPoint);
fU+=fUd;
}
fV+=fVd;
}
}
else
{
// For each tile
for (int vTile=0; vTile<nTileCountV; vTile++)
{
for (int uTile=0; uTile<nTileCountU; uTile++)
{
// For each vertices
for (int v=0; v<nVertexTileCount; v++)
{
float fV=(float)((v+1)>>1)/(float)(nVertexTileCount>>1);
for (int u=0; u<nVertexTileCount; u++)
{
// rotate
tileDesc &desc=getUIPatch (p).getTileDesc (uTile+vTile*nTileCountU);
int nRotate=4-desc.getLayer(std::min (desc.getNumLayer()-1, rTess.TransitionType-1)).Rotate;
int nCase=desc.getCase();
float fU=(float)((u+1)>>1)/(float)(nVertexTileCount>>1);
int nIndex=mpcopy+vTile*nVertexTileCount*nVertexTileCount*nTileCountU+v*nVertexTileCount*nTileCountU+
uTile*nVertexTileCount+u;
Point3 vRight=(vTt[(2+nRotate)&3][nCase]-vTt[(3+nRotate)&3][nCase])*fV+vTt[(3+nRotate)&3][nCase];
Point3 vLeft=(vTt[(1+nRotate)&3][nCase]-vTt[(0+nRotate)&3][nCase])*fV+vTt[(0+nRotate)&3][nCase];
Point3 vPoint=(vRight-vLeft)*fU+vLeft;
pMesh->setMapVert (nChannel, nIndex, vPoint);
}
}
}
}
}
}
}
}
}
}
}
}
if (Build&PART_TOPO)
{
pMesh->InvalidateTopologyCache();
//pMesh->BuildStripsAndEdges();
}
if (Build&PART_GEOM)
{
pMesh->InvalidateGeomCache();
}
ValidGeom=FOREVER;
ValidTopo=FOREVER;
ValidTexmap=FOREVER;
ValidSelect=FOREVER;
ValidDisplay=FOREVER;
for (int nf=0; nf<mesh.numFaces; nf++)
{
if (mesh.faceSel[nf])
int toto=0;
}
ticks=CTime::getPerformanceTime ()-ticks;
nldebug ("%f", CTime::ticksToSecond(ticks));
}
// Get tessel level of a patch
void RPatchMesh::GetPatchTess (int nPatch, int& nUTess, int& nVTess)
{
// Check size
nlassert (nPatch<(int)getUIPatchSize());
// Return tessel level depending tessel of the pathmesh and count of tile in the patch
nUTess=1<<max (0, rTess.TileTesselLevel+getUIPatch (nPatch).NbTilesU);
nVTess=1<<max (0, rTess.TileTesselLevel+getUIPatch (nPatch).NbTilesV);
}
// Display
int RPatchMesh::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags, PatchMesh& patch)
{
//TODO: Implement the displaying of the object here
// Update the mesh
BuildMesh (t, patch);
// Draw the mesh
GraphicsWindow *gw = vpt->getGW();
Matrix3 mat = inode->GetObjectTM(t);
gw->setTransform(mat);
// Becarful with sublevel selection
mesh.dispFlags=0;
switch (GetSelLevel())
{
case EP_VERTEX:
mesh.SetDispFlag(DISP_VERTTICKS|DISP_SELVERTS);
mesh.selLevel = MESH_VERTEX;
break;
case EP_EDGE:
case EP_PATCH:
case EP_TILE:
mesh.SetDispFlag(DISP_SELEDGES);
mesh.selLevel = MESH_EDGE;
break;
default:
mesh.SetDispFlag(0);
mesh.selLevel = MESH_OBJECT;
break;
}
if (paint)
{
mesh.SetDispFlag(DISP_SELEDGES);
mesh.selLevel = MESH_EDGE;
}
// Go
mesh.render( gw, inode->Mtls(),
(flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | ((flags&DISP_SHOWSUBOBJECT)?COMP_OBJSELECTED:0),
inode->NumMtls());
// Draw vector
if ((GetSelLevel()==EP_VERTEX)&&(inode->Selected()))
{
UpdateBinding (patch, t);
// Set new flags
patch.SetDispFlag(DISP_VERTTICKS|DISP_SELVERTS);
patch.selLevel=PATCH_VERTEX;
DWORD dw=gw->getRndLimits();
BitArray bit;
bit.SetSize (patch.numPatches);
bit.ClearAll ();
if ((dw&GW_PICK)==0)
{
// Hide all patch
for (int nP=0; nP<patch.numPatches; nP++)
{
if (patch.patches[nP].flags&PATCH_HIDDEN)
bit.Set (nP);
patch.patches[nP].flags|=PATCH_HIDDEN;
}
}
patch.render( gw, inode->Mtls(),
(flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | ((flags&DISP_SHOWSUBOBJECT)?COMP_OBJSELECTED:0),
inode->NumMtls());
if ((dw&GW_PICK)==0)
{
// Hide all patch
for (int nP=0; nP<patch.numPatches; nP++)
{
if (!bit[nP])
patch.patches[nP].flags&=~PATCH_HIDDEN;
}
}
}
// Point binded
if (inode->Selected())
{
gw->setColor(LINE_COLOR, 0, 0, 0);
for (int i=0; i<patch.numVerts; i++)
{
if (getUIVertex (i).Binding.bBinded)
{
// draw the point
gw->marker (&patch.verts[i].p, DOT_MRKR);
}
}
}
// A
// -
// B C
// -
// -
// D
// Draw the arrow
if (GetSelLevel()==EP_PATCH)
{
for (int i=0; i<patch.numPatches; i++)
{
if (patch.patches[i].type==PATCH_QUAD)
{
Point3 a,b,c,d;
Point3 p[2];
// 4 points
a=patch.patches[i].interp(&patch,0.5f,1.f/6.f);
b=patch.patches[i].interp(&patch,0.5f-1.f/6.f,1.f/3.f);
c=patch.patches[i].interp(&patch,0.5f+1.f/6.f,1.f/3.f);
d=patch.patches[i].interp(&patch,0.5f,5.f/6.f);
// draw the point
p[0]=a;
p[1]=b;
gw->polyline (2, p, NULL, NULL, FALSE, NULL);
p[1]=c;
gw->polyline (2, p, NULL, NULL, FALSE, NULL);
p[1]=d;
gw->polyline (2, p, NULL, NULL, FALSE, NULL);
}
}
}
return 0;
}
// Return a tile desc
tileDesc& RPatchMesh::getTileDesc (int nTile)
{
int patch=nTile/NUM_TILE_SEL;
int tile=nTile%NUM_TILE_SEL;
int tileY=tile/MAX_TILE_IN_PATCH;
int tileX=tile%MAX_TILE_IN_PATCH;
tile=tileY*(1<<getUIPatch (patch).NbTilesU)+tileX;
return getUIPatch (patch).getTileDesc (tile);
}
// Set a tile desc
void RPatchMesh::setTileDesc (int nTile, const tileDesc& desc)
{
int patch=nTile/NUM_TILE_SEL;
int tile=nTile%NUM_TILE_SEL;
int tileY=tile/MAX_TILE_IN_PATCH;
int tileX=tile%MAX_TILE_IN_PATCH;
tile=tileY*(1<<getUIPatch (patch).NbTilesU)+tileX;
getUIPatch (patch).getTileDesc (tile)=desc;
}
// Turn selected patch
void RPatchMesh::TurnPatch(PatchMesh *patch)
{
// For each patch
for (int p=0; p<patch->numPatches; p++)
{
// Selected ?
if (patch->patchSel[p])
{
// Tessel U and V
int nOldU=1<<(getUIPatch (p).NbTilesU);
int nOldV=1<<(getUIPatch (p).NbTilesV);
// Reverse UV count
int tmp=getUIPatch (p).NbTilesU;
getUIPatch (p).NbTilesU=getUIPatch (p).NbTilesV;
getUIPatch (p).NbTilesV=tmp;
// Copy old array
UI_PATCH old=getUIPatch (p);
// Turn tile array
int u, v;
for (v=0; v<nOldV; v++)
for (u=0; u<nOldU; u++)
{
int newU=nOldV-v-1;
int newV=u;
getUIPatch (p).getTileDesc (newU+newV*nOldV)=old.getTileDesc (u+v*nOldU);
// Rotate each layer
getUIPatch (p).getTileDesc (newU+newV*nOldV).rotate (3);
}
// Turn vertex color
// Tessel U and V
nOldU++;
nOldV++;
// Turn tile array
for (v=0; v<nOldV; v++)
for (u=0; u<nOldU; u++)
{
int newU=nOldV-v-1;
int newV=u;
getUIPatch (p).setColor (newU+newV*nOldV, old.getColor (u+v*nOldU));
}
}
}
// Check binding infos
for (int v=0; v<patch->numVerts; v++)
{
// Binded ?
if (getUIVertex (v).Binding.bBinded)
{
// On a patch turned ?
int nPatch=getUIVertex (v).Binding.nPatch;
if (patch->patchSel[nPatch])
{
// Ok, turn the bind info..
getUIVertex (v).Binding.nEdge--;
getUIVertex (v).Binding.nEdge&=3;
}
}
}
}
// Turn selected patch
void RPatchMesh::RotateTiles (PatchMesh *patch, int rot)
{
// For each patch
for (int p=0; p<patch->numPatches; p++)
{
// Tessel U and V
int nU=1<<(getUIPatch (p).NbTilesU);
int nV=1<<(getUIPatch (p).NbTilesV);
// Turn tile array
for (int v=0; v<nV; v++)
for (int u=0; u<nU; u++)
{
// Rotate each layer
getUIPatch (p).getTileDesc (u+v*nU).rotate (rot);
}
}
}
// Turn selected patch
/*void RPatchMesh::flipTilesUpDown (PatchMesh *patch)
{
// For each patch
for (int p=0; p<patch->numPatches; p++)
{
// Tessel U and V
int nU=1<<(getUIPatch (p).NbTilesU);
int nV=1<<(getUIPatch (p).NbTilesV);
// Copy old array
UI_PATCH old=getUIPatch (p);
// Turn tile array
for (int v=0; v<nV; v++)
for (int u=0; u<nU; u++)
{
// Rotate each layer
getUIPatch (p).getTileDesc (u+v*nU) = old.getTileDesc (u+(nV-1-v)*nU);
getUIPatch (p).getTileDesc (u+v*nU).flipUpDown ();
}
}
}*/
// Copy operator
#ifdef USE_CACHE
void RPatchMesh::operator= (const RPatchMesh& fromOb)
{
DeepCopy (const_cast<RPatchMesh*>(&fromOb), PART_GEOM|SELECT_CHANNEL|PART_SUBSEL_TYPE|PART_DISPLAY|PART_TOPO|TEXMAP_CHANNEL);
}
#endif // USE_CACHE
CBankManager RPatchMesh::manager;