// This file is distributed under a BSD license. See LICENSE.txt for details. #include "genmesh.hpp" #include "genmaterial.hpp" #include "genbitmap.hpp" #include "genoverlay.hpp" #include "genscene.hpp" #include "engine.hpp" #include "_util.hpp" #include "genminmesh.hpp" #define SCRIPTVERIFY(x) {if(!(x)) return 0;} // rules: // - first all SCRIPTVERIFY // - then CheckMesh() // - after CheckMesh() you may not return 0 // // if return 0, then caller calls Release() for every argument. // if return !=0, then routine calls Release() for every argument // (except what it may return) /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ void GenMeshElem::InitElem() { Mask = 0; Id = 0; Select = 0; Used = 1; } void GenMeshElem::SelElem(sU32 mask,sBool state,sInt mode) { switch(mode) { case MSM_ADD: if(state) Mask |= mask; break; case MSM_SUB: if(state) Mask &= ~mask; break; case MSM_SET: if(state) Mask |= mask; else Mask &= ~mask; break; case MSM_SETNOT: if(state) Mask &= ~mask; else Mask |= mask; break; } } void GenMeshElem::SelLogic(sU32 smask1,sU32 smask2,sU32 dmask,sInt mode) { sBool s1,s2; s1 = (Mask & smask1) ? 1 : 0; s2 = (Mask & smask2) ? 1 : 0; if(mode&4) s1 ^= 1; if(mode&8) s2 ^= 1; switch(mode&3) { case 0: s1 |= s2; break; case 1: s1 &= s2; break; case 2: s1 ^= s2; break; } if(mode&16) s1 ^= 1; if(s1) Mask |= dmask; else Mask &= ~dmask; } void GenMeshVert::Init() { sInt i; InitElem(); Next = -1; First = -1; Temp = -1; Temp2 = -1; ReIndex = -1; for(i=0;i<4;i++) { Matrix[i] = 0xff; Weight[i] = 0; } } void GenMeshEdge::Init() { InitElem(); Next[0] = -1; Next[1] = -1; Prev[0] = -1; Prev[1] = -1; Face[0] = -1; Face[1] = -1; Vert[0] = -1; Vert[1] = -1; Temp[0] = -1; Temp[1] = -1; Crease = 0; } void GenMeshFace::Init() { InitElem(); Material = 1; Edge = -1; Temp = -1; Temp2 = 0; Temp3 = 0; } /****************************************************************************/ void GenSimpleFace::Init(sInt Verts) { VertexCount = Verts; Vertices = new sVector[VertexCount]; sVERIFY(VertexCount < 64); } void GenSimpleFace::Exit() { delete[] Vertices; Vertices = 0; } void GenSimpleFace::AddVertex(const sVector &v) { Vertices[VertexCount++] = v; } static sInt ClassifyVert(const sVector &v,const sVector &plane) { static const sF32 epsilon = 1e-3f; // 1 mm sF32 dot = v.Dot3(plane) + plane.w; if(dot > epsilon) // front / in return 0; else if(dot < -epsilon) // back / out return 1; else // on return 2; } ClipCode GenSimpleFace::Clip(const sVector &plane,GenSimpleFace *faces) const { static const sF32 div_epsilon = 1e-20f; sF32 d1,d2,t; sInt lastside,side; sInt lasti,i; sInt cross; sVector v; sBool allOn = sTRUE; // faces[0].Init(VertexCount + 2); // faces[1].Init(VertexCount + 2); faces[0].VertexCount = 0; faces[1].VertexCount = 0; cross = 0; lasti = VertexCount - 1; lastside = ClassifyVert(Vertices[lasti],plane); for(i=0;iClassId == KC_SMESH); os = (GenSimpleMesh *) o; Faces.Copy(os->Faces); } void GenSimpleMesh::Clear() { sInt i; for(i=0;iFaces.Count;i++) AddFace(other->Faces[i]); } void GenSimpleMesh::AddQuad(const sVector &v1,const sVector &v2,const sVector &v3,const sVector &v4) { GenSimpleFace *fc = Faces.Add(); fc->Init(4); fc->VertexCount = 0; fc->AddVertex(v1); fc->AddVertex(v2); fc->AddVertex(v3); fc->AddVertex(v4); } void GenSimpleMesh::AddFace(const GenSimpleFace &face) { sInt i; GenSimpleFace *fc = Faces.Add(); fc->Init(face.VertexCount); for(i=0;iVertices[i] = face.Vertices[i]; } void GenSimpleMesh::Cube(const sAABox &box) { sVector Verts[8]; sInt i; Clear(); // prepare vertices for(i=0;i<8;i++) { Verts[i].x = (i&1) ? box.Max.x : box.Min.x; Verts[i].y = (i&2) ? box.Max.y : box.Min.y; Verts[i].z = (i&4) ? box.Max.z : box.Min.z; Verts[i].w = 1.0f; } // add faces AddQuad(Verts[0],Verts[2],Verts[3],Verts[1]); // front AddQuad(Verts[4],Verts[6],Verts[2],Verts[0]); // left AddQuad(Verts[5],Verts[7],Verts[6],Verts[4]); // back AddQuad(Verts[1],Verts[3],Verts[7],Verts[5]); // right AddQuad(Verts[2],Verts[6],Verts[7],Verts[3]); // top AddQuad(Verts[5],Verts[4],Verts[0],Verts[1]); // bottom } sBool GenSimpleMesh::CSGSplitR(const GenSimpleFace &face,const sVector *planes,sInt plane,sInt nPlanes,sBool keepOut) { GenSimpleFace sides[2]; sVector sidev[2][64]; sBool split[2]; sInt i; sBool ret; sFatal("dierk hat hier das allokationschema geändert und nicht getestet..."); sides[0].Vertices = sidev[0]; sides[1].Vertices = sidev[1]; face.Clip(planes[plane],sides); sVERIFY(sides[0].VertexCount <= 64); sVERIFY(sides[1].VertexCount <= 64); for(i=0;i<2;i++) { if(sides[i].VertexCount < 3) // degenerate faces can't be split split[i] = sFALSE; else { if(plane == nPlanes - 1) // leaf, check whether face inside volume split[i] = sides[i].Inside(planes,nPlanes) == keepOut; else split[i] = CSGSplitR(sides[i],planes,plane+1,nPlanes,keepOut); } } if(split[0] || split[1]) // we have splits, add all remaining polys. { for(i=0;i<2;i++) if(sides[i].VertexCount >= 3 && !split[i]) AddFace(sides[i]); ret = sTRUE; } else ret = sFALSE; // sides[0].Exit(); // sides[1].Exit(); return ret; } void GenSimpleMesh::CSGAgainst(const sVector *planes,sInt nPlanes,sBool keepOut) { sInt i,inFaceCount; GenSimpleFace *faces; sBool split; inFaceCount = Faces.Count; faces = Faces.Array; // somewhat hackish, but this has to make do for now Faces.Array = new GenSimpleFace[16]; Faces.Alloc = 16; Faces.Count = 0; for(i=0;iRelease(); delete[] Planes; } void GenSimpleBrush::Cube(const sAABox &box) { Mesh->Cube(box); PlaneCount = 6; Planes = new sVector[PlaneCount]; Planes[0].Init(-1.0f, 0.0f, 0.0f, box.Min.x); Planes[1].Init( 1.0f, 0.0f, 0.0f,-box.Max.x); Planes[2].Init( 0.0f,-1.0f, 0.0f, box.Min.y); Planes[3].Init( 0.0f, 1.0f, 0.0f,-box.Max.y); Planes[4].Init( 0.0f, 0.0f,-1.0f, box.Min.z); Planes[5].Init( 0.0f, 0.0f, 1.0f,-box.Max.z); BBox = box; } void GenSimpleBrush::CSGAgainst(const GenSimpleBrush &other,sBool keepOut) { if(BBox.Intersects(other.BBox)) Mesh->CSGAgainst(other.Planes,other.PlaneCount,sTRUE); } /****************************************************************************/ /****************************************************************************/ GenMesh::GenMesh() { ClassId = KC_MESH; Vert.Init(16); Edge.Init(16); Face.Init(16); Mtrl.Init(16); Coll.Init(1); Lgts.Init(1); Parts.Init(1); #if !sINTRO _VertMask = 0; _VertSize = 0; #endif VertAlloc = 0; VertCount = 0; VertBuf = 0; Stripped = sFALSE; #if !sINTRO BoneMatrix.Init(); BoneCurve.Init(); KeyCount = 0; CurveCount = 0; KeyBuf = 0; Anim0 = 0; Anim1 = 16; #endif PreparedMesh = 0; Pivot = -1; GotNormals = sFALSE; Mtrl.Count = 2; // null-material Mtrl[0].Material = 0; Mtrl[0].Pass = 0; Mtrl[1].Material = GenOverlayManager->DefaultMat; Mtrl[1].Material->AddRef(); Mtrl[1].Pass = 0; #if !sPLAYER WireMesh = 0; WireFlags = 0; WireSelMask = 0; #endif } GenMesh::~GenMesh() { sInt i; #if !sPLAYER UnPrepareWire(); #endif for(i=1;iRelease(); #if !sINTRO if(KeyBuf) delete[] KeyBuf; #endif if(VertBuf) delete[] VertBuf; Vert.Exit(); Edge.Exit(); Face.Exit(); Mtrl.Exit(); Coll.Exit(); Lgts.Exit(); Parts.Exit(); UnPrepare(); #if !sINTRO BoneMatrix.Exit(); BoneCurve.Exit(); #endif } void GenMesh::Copy(KObject *o) { GenMesh *om; sInt i;//,j; sVERIFY(o->ClassId==KC_MESH); om = (GenMesh *)o; for(i=1;iRelease(); Vert.Copy(om->Vert); Edge.Copy(om->Edge); Face.Copy(om->Face); Mtrl.Copy(om->Mtrl); Coll.Copy(om->Coll); Lgts.Copy(om->Lgts); Parts.Copy(om->Parts); for(i=1;iAddRef(); PreparedMesh = 0; #if !sPLAYER WireMesh = 0; WireFlags = 0; WireSelMask = 0; #endif Init(om->VertMask(),om->VertAlloc); sVERIFY(VertSize()==om->VertSize()); sCopyMem4((sU32 *)VertBuf,(sU32 *)om->VertBuf,om->VertSize()*om->VertCount*4); VertCount = om->VertCount; #if !sINTRO BoneMatrix.Copy(om->BoneMatrix); BoneCurve.Copy(om->BoneCurve); KeyCount = om->KeyCount; CurveCount = om->CurveCount; if(om->KeyBuf) { KeyBuf = new sF32[KeyCount*CurveCount]; sCopyMem(KeyBuf,om->KeyBuf,KeyCount*CurveCount*4); } Anim0 = om->Anim0; Anim1 = om->Anim1; #endif Pivot = om->Pivot; GotNormals = om->GotNormals; } sU32 GenMesh::Features2Mask(sInt colorSets,sInt uvSets) { sVERIFY(colorSets>=0 && colorSets<=1); sVERIFY(uvSets>=1 && uvSets<=4); return sGMF_POS|sGMF_NORMAL|sGMF_TANGENT|(((1<=VertAlloc) { ns = sMax(vertcount,VertAlloc*2-VertAlloc/2); nd = new sVector[ns*VertSize()]; sCopyMem4((sU32 *)nd,(sU32 *)VertBuf,VertSize()*4*VertCount); sSetMem4((sU32 *)(nd+VertSize()*VertCount),0,VertSize()*4*(ns-VertCount)); delete[] VertBuf; VertBuf = nd; VertAlloc = ns; } VertCount = vertcount; } /****************************************************************************/ /****************************************************************************/ GenMeshFace *GenMesh::GetFace(sU32 i) { return &Face.Array[GetEdge(i)->Face[i&1]]; } GenMeshFace *GenMesh::GetFaceI(sU32 i) { return &Face.Array[GetEdge(i)->Face[~i&1]]; } GenMeshVert *GenMesh::GetVert(sU32 i) { return &Vert.Array[GetEdge(i)->Vert[i&1]]; } sInt GenMesh::GetFaceId(sU32 i) { return GetEdge(i)->Face[i&1]; } sInt GenMesh::GetVertId(sU32 i) { return GetEdge(i)->Vert[i&1]; } sInt GenMesh::NextFaceEdge(sU32 i) { return GetEdge(i)->Next[i&1]; } sInt GenMesh::PrevFaceEdge(sU32 i) { return GetEdge(i)->Prev[i&1]; } sInt GenMesh::NextVertEdge(sU32 i) { return GetEdge(i)->Prev[i&1]^1; } sInt GenMesh::PrevVertEdge(sU32 i) { return GetEdge(i)->Next[~i&1]; } sInt GenMesh::SkipFaceEdge(sU32 i,sInt num) { if(num<0) { while(num++) i = PrevFaceEdge(i); } else { while(num--) i = NextFaceEdge(i); } return i; } sInt GenMesh::SkipVertEdge(sU32 i,sInt num) { if(num<0) { while(num++) i = PrevVertEdge(i); } else { while(num--) i = NextVertEdge(i); } return num; } sInt GenMesh::AddPivot() { sInt i,vs; if(Pivot==-1) { Vert.Resize(Vert.Count+1); Realloc(Vert.Count); Pivot = Vert.Count-1; vs = VertSize(); for(i=0;i VertCount) { nd = new sVector[VertCount*VertSize()]; sCopyMem4((sU32 *)nd,(sU32 *)VertBuf,VertSize()*4*VertCount); delete[] VertBuf; VertBuf = nd; VertAlloc = VertCount; } } sInt GenMesh::AddVert() { sInt c; c = Vert.Count; Realloc(c+1); Vert.AtLeast(c+1); Vert.Count++; return c; } sInt GenMesh::AddNewVert() { sInt v; v = AddVert(); Vert[v].Init(); Vert[v].First = Vert[v].Next = Vert[v].ReIndex = v; return v; } sInt GenMesh::AddCopiedVert(sInt src) { sInt v; v = AddVert(); Vert[v] = Vert[src]; Vert[v].ReIndex = v; return v; } void GenMesh::SplitFace(sU32 i0,sU32 i1,sU32 dmask,sInt dmode) { sInt ee,f0,f1,p0,p1; sU32 i; sVERIFY(GetFaceId(i0)==GetFaceId(i1)); sVERIFY(i0!=i1); p0 = PrevFaceEdge(i0); p1 = PrevFaceEdge(i1); f0 = GetFaceId(i0); /*ee = Edge.Count; Edge.AtLeast(ee+1); Edge.Count++; f1 = Face.Count; Face.AtLeast(f1+1); Face.Count++;*/ ee = Edge.Count; Edge.Add(); f1 = Face.Count; Face.Add(); register GenMeshEdge *Edge = this->Edge.Array; register GenMeshFace *Face = this->Face.Array; Edge[ee] = Edge[i0/2]; Edge[ee].Crease = 0; // kill crease flags Edge[ee].Sel(dmask,1,dmode); Edge[ee].Vert[0] = GetVertId(i1); Edge[ee].Vert[1] = GetVertId(i0); Edge[ee].Face[0] = f0; Edge[ee].Face[1] = f0; Edge[ee].Next[0] = i0; Edge[ee].Next[1] = i1; Edge[ee].Prev[0] = p1; Edge[ee].Prev[1] = p0; Edge[ee].Temp[0] = -1; Edge[ee].Temp[1] = -1; Edge[i0>>1].Prev[i0&1] = ee*2; Edge[p0>>1].Next[p0&1] = ee*2+1; Edge[i1>>1].Prev[i1&1] = ee*2+1; Edge[p1>>1].Next[p1&1] = ee*2; Face[f1] = Face[f0]; Face[f1].Sel(dmask,1,dmode); Face[f0].Edge = i0; Face[f1].Edge = i1; i = i1; do { sVERIFY(GetFaceId(i)==f0); sVERIFY(NextFaceEdge(PrevFaceEdge(i)) == i); sVERIFY(PrevFaceEdge(NextFaceEdge(i)) == i); Edge[i/2].Face[i&1] = f1; i = NextFaceEdge(i); } while(i!=i1); #if !sPLAYER //just checking! i = i0; do { sVERIFY(GetFaceId(i)==f0); sVERIFY(NextFaceEdge(PrevFaceEdge(i)) == i); sVERIFY(PrevFaceEdge(NextFaceEdge(i)) == i); i = NextFaceEdge(i); } while(i!=i0); #endif } void GenMesh::SplitBridge(sU32 a,sU32 d,sInt &va,sInt &vb,sU32 dmask,sInt dmode,sInt *dv1,sInt *dv2) { sU32 e,p0,p1,n0,n1; sInt v0,v1,cf,i,lc; //e = Edge.Count; Edge.AtLeast(e+1); Edge.Count = e+1; e = Edge.Count; Edge.Add(); v0 = va; Vert[v0].Sel(dmask,1,dmode); Vert[v0].First = v0; Vert[v0].Next = v0; a = a^1; p0 = PrevFaceEdge(d); n1 = NextFaceEdge(a); v1 = GetVertId(n1); sVERIFY(Vert[v1].First == GetVert(d)->First); cf=0; // cumulative crease flag if(n1==d) { p0 = e*2+1; n1 = e*2; } else { for(i=n1;i!=d;i=PrevVertEdge(i)) { if(Edge[i/2].Crease) { cf|=Edge[i/2].Crease; lc=i; } } } register GenMeshEdge *Edge = this->Edge.Array; Edge[e] = Edge[a/2]; Edge[e].Crease = cf; Edge[e].Sel(dmask,1,dmode); Edge[e].Vert[0] = v0; Edge[e].Vert[1] = v1; Edge[e].Face[0] = GetFaceId(d); Edge[e].Face[1] = GetFaceId(a); Edge[e].Next[0] = n0 = d; Edge[e].Next[1] = n1; Edge[e].Prev[0] = p0; Edge[e].Prev[1] = p1 = a; Edge[e].Temp[0] = -1; Edge[e].Temp[1] = -1; Edge[n0/2].Prev[n0&1] = Edge[p0/2].Next[p0&1] = e*2; Edge[n1/2].Prev[n1&1] = Edge[p1/2].Next[p1&1] = e*2+1; if(cf) { v0 = GetVertId(PrevVertEdge(lc)^1); v1 = AddCopiedVert(v0); Vert[v1].Sel(dmask,1,dmode); Edge[lc/2].Vert[lc&1] = v1; if(dv1) { *dv1 = v0; *dv2 = v1; } } else if(dv1) *dv1 = -1; FixVertCycle(e*2); FixVertCycle(e*2+1); va = GetVertId(e*2); vb = GetVertId(n1); } sInt GenMesh::AddEdge(sInt v0,sInt v1,sInt face) { sInt v0f,v1f; sInt e,ee; v0f = Vert[v0].First; v1f = Vert[v1].First; if(Edge.Count) { e = ee = Vert[v1f].Temp2; if(e != -1) { do { sVERIFY(Vert[Edge[e].Vert[0]].First == v1f); if(Edge[e].Face[1] == -1 && Edge[e].Vert[1] == v0f) { Edge[e].Vert[1] = v0; Edge[e].Face[1] = face; Face[face].Edge = e*2+1; return e*2+1; } e = Edge[e].Temp[0]; } while(e != ee); } } e = Edge.Count; Edge.AtLeast(e+1); Edge.Count = e+1; Edge[e].Init(); Edge[e].Vert[0] = v0; Edge[e].Vert[1] = v1f; Edge[e].Face[0] = face; Edge[e].Face[1] = -1; if(Vert[v0f].Temp2 != -1) { ee = Vert[v0f].Temp2; Edge[e].Temp[0] = Edge[ee].Temp[0]; Edge[ee].Temp[0] = e; } else { Edge[e].Temp[0] = e; Vert[v0f].Temp2 = e; } Face[face].Edge = e*2; return e*2; } void GenMesh::MakeFace(sInt face,sInt nedges,...) { sInt i,t,e; sInt *edges; edges = &nedges + 1; Face[face].Init(); Face[face].Edge = edges[0]; t = edges[nedges-1]; for(i=0;i=0 && Face[i].Edge=0 && Vert[i].Next=0 && Edge[i].Next[0]=0 && Edge[i].Next[1]=0 && Edge[i].Prev[0]=0 && Edge[i].Prev[1]=0 && Edge[i].Face[0]=0 && Edge[i].Face[1]=0 && Edge[i].Vert[0]=0 && Edge[i].Vert[1]First == GetVert(NextFaceEdge(i*2 ) )->First); sVERIFY(GetVert(i*2 )->First == GetVert(NextFaceEdge(i*2+1) )->First); sVERIFY(GetVert(i*2 )->First == GetVert(PrevFaceEdge(i*2 )^1)->First); sVERIFY(GetVert(i*2+1)->First == GetVert(PrevFaceEdge(i*2+1)^1)->First); // the following test makes sense, but is currently out because ReadCompact // produces slightly broken meshes (no crease, yet double vertices nonetheless) /*if(!Edge[i].Crease) { sVERIFY(GetVertId(i*2 ) == GetVertId(PrevVertEdge(i*2 ))); sVERIFY(GetVertId(i*2+1) == GetVertId(PrevVertEdge(i*2+1))); }*/ } } #endif void GenMesh::ReIndex() { sInt i,j,vc,ec,cc; vc = Vert.Count; for(i=0;iSelect; s1 = GetFaceI(i)->Select; if((Edge[i/2].Crease & sGMF_NORMALS) || mode) s1 = 0; return s0 && !s1; } /****************************************************************************/ /****************************************************************************/ void GenMesh::Mask2Sel(sU32 mask) { sInt i; if(mask&0x00ff0000) for(i=0;i>16))!=0); if(mask&0x0000ff00) for(i=0;i> 8))!=0); if(mask&0x000000ff) for(i=0;iSelect = 1; e = NextFaceEdge(e); } while(e!=ee); } } } void GenMesh::Edge2Vert(sInt uvs) { sInt i,j; j = VertMap(sGMI_UV0); for(i=0;i0.5f) { GetVert(i)->Select=1; GetVert(NextFaceEdge(i))->Select=1; } } } } void GenMesh::Vert2FaceEdge() { sInt i,e,ee; sBool all; for(i=0;iSelect && GetVert(i*2+1)->Select; for(i=0;iSelect) all = 0; e = NextFaceEdge(e); } while(ee!=e && all); Face[i].Select = all; } } void GenMesh::CalcNormal(sVector &n,sInt v0,sInt v1,sInt v2) { sVector t1,t2; t1.Sub3(VertBuf[v1 * VertSize()],VertBuf[v0 * VertSize()]); t2.Sub3(VertBuf[v2 * VertSize()],VertBuf[v0 * VertSize()]); n.Cross3(t1,t2); } void GenMesh::CalcFaceNormal(sVector &n,sInt e) { CalcNormal(n,GetVertId(PrevFaceEdge(e)),GetVertId(e), GetVertId(NextFaceEdge(e))); } void GenMesh::CalcFaceNormalAccurate(sVector &n,sInt f) { sInt v0,e,ee,ne; sF32 l; e = ee = Face[f].Edge; v0 = GetVertId(PrevFaceEdge(e))*VertSize(); do { ne = NextFaceEdge(e); CalcNormal(n,GetVertId(PrevFaceEdge(e)),GetVertId(e),GetVertId(ne)); e = ne; } while((l = n.Dot3(n)) > 1e-40f && e != ee); if(l >= 1e-40f) n.Scale3(sFInvSqrt(l)); else n.Init3(1,0,0); } void GenMesh::CalcFacePlane(sVector &p,sInt f) { CalcFaceNormalAccurate(p,f); p.w = -p.Dot3(VertPos(GetVertId(Face[f].Edge))); } void GenMesh::CalcFaceCenter(sVector &m,sInt f) { sInt e,ee,cnt; e = ee = Face[f].Edge; m.Init(0,0,0,1); cnt = 0; do { m.Add3(VertPos(GetVertId(e))); cnt++; e = NextFaceEdge(e); } while(e!=ee); m.Scale3(1.0f / cnt); } void GenMesh::CalcBBox(sAABox &box) { sInt i; All2Sel(1,MAS_FACE); Face2Vert(); box.Min.Init( 1e+15f, 1e+15f, 1e+15f, 1.0f); box.Max.Init(-1e+15f, -1e+15f, -1e+15f, 1.0f); for(i=0;ix)[j] - (&vc.x)[j]) / (&vs.x)[j]; r += t * t; } Vert[i].Select = (r <= 1.0f); } Vert2FaceEdge(); Sel2Mask(dmask,dmode); } /****************************************************************************/ void GenMesh::Ring(sInt segments,sU32 dmask,sF32 radius,sF32 phase,sInt arc) { sInt i,in,ip; sInt sj; sVector *vp; GenMeshEdge *ed; sInt count; sVERIFY(arc0) count = segments - arc + 2; else count = segments; Vert.AtLeast(count); Edge.AtLeast(count); Edge.Count=count; Face.AtLeast(2); Face.Count=2; Face[0].Init(); Face[0].Edge = 0; Face[1].Init(); Face[1].Edge = 1; sj = VertMap(sGMI_UV0); for(i=0;i0) { vp->x = 0; vp->y = 0; } else { vp->x = sFSin(phase+i*sPI2F/(segments))*radius; vp->y = -sFCos(phase+i*sPI2F/(segments))*radius; } vp->w = 1.0f; if(sj!=-1) { vp[sj].x = i*1.0f/count; vp[sj].w = 1.0f; } in=(i+1)%count; ip=(i+count-1)%count; ed = &Edge[i]; ed->Init(); ed->Next[0] = 2*in; ed->Next[1] = 2*ip+1; ed->Prev[0] = 2*ip; ed->Prev[1] = 2*in+1; ed->Face[0] = 0; ed->Face[1] = 1; ed->Vert[0] = i; ed->Vert[1] = in; } All2Mask(dmask); } /****************************************************************************/ void GenMesh::Extrude(sU32 dmask,sInt dmode,sInt mode) { sInt i,e,ec,va,vb,ov,o1,s1; ec = Edge.Count; for(i=0;i>= 1; vmask >>= 1; } return omask; } void GenMesh::Subdivide(sF32 alpha) { sInt i,j,k,count,e,ee,c,v,vv; sInt va0,va1,vb0,vb1,va,vb; sInt ec,s0,s1; sU32 Temp[128]; sInt fc = Face.Count; sInt ovc = Vert.Count; sInt vs = VertSize(); // face.temp = first new edge // face.temp2 = center // edge.temp[0] // edge.temp[1] // vert.temp = duplicated vertex for storing old value // vert.temp2 = vertex->edge ptr // calculate center positions for(i=0;iTemp2!=-1) Temp[k++] = GetFace(e)->Temp2; else c = e; if(GetVertId(e) == i) ec |= Edge[e/2].Crease; e = NextVertEdge(e); } while(e!=ee); sInt vs = VertSize(); sVector *vd = VertBuf + Vert[i].ReIndex * vs; sVector *vo = VertBuf + i * vs; // orig if(c==-1) // no boundary { // calc weights sF32 w1 = 4.0f * alpha / (k * k); sF32 w2 = 1.0f - alpha * 4.0f / k; sU32 mask = MakeSubdMask(ec,VertMask()); // calc vert (attribute by attribute) for(j=0;j>=1) { if(mask & 1) // crease, just copy vd[j] = vo[j]; else // weight verts accordingly { vd[j].Scale4(vo[j],w2); for(sInt n=0;nSelect); vb = GetVertId(c^1); // calc weights sF32 w1 = alpha * 0.125f; sF32 w2 = 1.0f - 2.0f * w1; sVector *vertA = VertBuf + va * vs; sVector *vertB = VertBuf + vb * vs; // calc vert (attribute by attribute) for(j=0;jSelect; s1 = GetFaceI(i)->Select; if(s0 || s1) { // split edge va = AddNewVert(); Vert[va].Mask = GetVert(i)->Mask | GetVert(SkipFaceEdge(i,2))->Mask; SplitBridge(NextVertEdge(i^1),PrevVertEdge(i^1),va,vb,0x100000,0); vb0 = GetVert(PrevFaceEdge(i^1))->Temp2; vb1 = GetVert(NextFaceEdge(i^1))->Temp2; va0 = GetVert(i)->Temp2; va1 = GetVert(NextFaceEdge(NextFaceEdge(i)))->Temp2; j = Edge[i/2].Crease; sVERIFY(va0!=-1 && va1!=-1 && vb0!=-1 && vb1!=-1); // calc boundary mask and vertices to weight in sInt mask = (s0 && s1) ? MakeSubdMask(~j,VertMask()) : 0; sInt vc0 = GetFace(i)->Temp2; sInt vc1 = GetFaceI(i)->Temp2; sInt vs = VertSize(); sVector *vd0 = VertBuf + va * vs; sVector *vd1 = VertBuf + vb * vs; // perform actual weighting for(j=0;j>=1) { sVector t0,t1; t0.Add4(VertBuf[va0*vs + j],VertBuf[va1*vs + j]); if(vd0 != vd1) t1.Add4(VertBuf[vb0*vs + j],VertBuf[vb1*vs + j]); if(mask & 1) { vd0[j].Scale4(t0,w2); if(vd0 != vd1) vd1[j].Scale4(t1,w2); t0.Add4(VertBuf[vc0*vs + j],VertBuf[vc1*vs + j]); vd0[j].AddScale4(t0,w1); if(vd0 != vd1) vd1[j].AddScale4(t0,w1); } else { vd0[j].Scale4(t0,0.5f); if(vd0 != vd1) vd1[j].Scale4(t1,0.5f); } } // store link to correct edge for face generation if(s0) GetFace(i)->Temp = i; if(s1) GetFaceI(i)->Temp = PrevFaceEdge(i^1); } } // create faces fc = Face.Count; for(i=0;iVertBuf + *data++; dx = dy = dz = 0.0f; for (i = 0; i < 4; i++) { sF32 weight = (sF32&) *data++; sMatrix* mtx = matrices + *data++; dx+=weight*(vec->x*mtx->i.x+vec->y*mtx->j.x+vec->z*mtx->k.x+mtx->l.x); dy+=weight*(vec->x*mtx->i.y+vec->y*mtx->j.y+vec->z*mtx->k.y+mtx->l.y); dz+=weight*(vec->x*mtx->i.z+vec->y*mtx->j.z+vec->z*mtx->k.z+mtx->l.z); } vec->x = dx; vec->y = dy; vec->z = dz; } return data; } sInt GenMesh::Bones(sF32 phase) { #if !sINTRO sU32 *data,*cptr; sF32 wgt; sInt i,j,mi,lm=0; data = RecBegin(BoneInner); sVERIFY(RBIndex+BoneMatrix.Count<1024); BonesModify(-1,phase); mi = RBIndex; RBIndex += BoneMatrix.Count; cptr = data; *data++ = 0; for(i=0;i0 && BoneCurve.Count>0) { i = (Anim0 + phase*(Anim1-Anim0))*1024; ki0 = (i/1024)%KeyCount; ki1 = (i/1024+1)%KeyCount; i &= 1023; f1 = i/1024.0f; cur = BoneCurve.Array; for(i=0;iMatrix].TransSRT[cur->Curve] = val; cur++; } } BoneMatrix[0].Matrix.InitSRT(BoneMatrix[0].TransSRT); mat.InitSRTInv(BoneMatrix[0].BaseSRT); mp[0].MulA(mat,BoneMatrix[0].Matrix); for(i=1;iReIndex; Vert[v].First = v0; Vert[v].Next = v0; e = i; do { Edge[e/2].Vert[e&1] = v; e = NextVertEdge(e); vn = GetVert(e)->ReIndex; if(Edge[e/2].Crease) { if(vn!=v && vn!=v0) { Vert[v].Next = vn; Vert[vn].First = v0; Vert[vn].Next = v0; } v = vn; } } while(e!=i); } void GenMesh::Crease(sInt selType,sU32 dmask,sInt dmode,sInt what) { sInt i,j,k,e,got,v0,v,vf; sBool sel; sVERIFY(!(what & 1)); for(i=0;iSelect && !GetFaceI(i)->Select; else if(selType==1) sel = Edge[i/2].Select; else sel = GetFace(i)->Select; if(sel) { if(!Edge[i/2].Crease) { for(j=0;j<2;j++) { k = i^j; v0 = GetVertId(k); vf = Vert[v0].First; got = 0; e = k; do { got |= Edge[e/2].Crease; e = NextVertEdge(e); } while(e!=k); if(got) // already atleast one crease on this vertex { v = AddCopiedVert(v0); Vert[v].Sel(dmask,1,dmode); Vert[v].First = vf; Vert[v0].Next = v; CopyVert(v,v0); do { sVERIFY(GetVertId(k)==v0); Edge[k/2].Vert[k&1] = v; k = NextVertEdge(k); } while(!Edge[k/2].Crease); } } } Edge[i/2].Crease|=what; // update crease flags } } } void GenMesh::UnCrease(sBool edge,sInt what) { sInt i; sBool sel; sVERIFY(!(what & 1)); for(i=0;iedge links in Temp for(i=0;iSelect) ? sTRUE : sFALSE; // accumulate on this side of the crease // (the loop construction is absolutely awful, fix that somehow) sVector accu,t,t1,t2,*v0,*v1,*v2; sF32 t1l,t2l; sBool wasExit,exit=sFALSE; v0 = VertBuf + GetVertId(e) * vs; v2 = VertBuf + GetVertId(NextFaceEdge(e)) * vs; accu.Init4(0,0,0,0); t2.Sub3(*v2,*v0); t2l = t2.Dot3(t2); do { wasExit = exit; // go to next vert, cycle variables if(GetFace(e)->Select) ok = sTRUE; t1 = t2; t1l = t2l; v1 = v2; if(!wasExit) v2 = VertBuf + GetVertId(NextFaceEdge(e)) * vs; else v2 = VertBuf + GetVertId(PrevFaceEdge(PrevVertEdge(e))) * vs; t2.Sub3(*v2,*v0); t2l = t2.Dot3(t2); if(component == 0) // calc normal { if(t1l * t2l > 1e-20f) { t.Cross3(t1,t2); accu.AddScale3(t,1.0f/(t1l * t2l)); } } else // calc tangent { sF32 c1 = v0[su].y - v1[su].y; sF32 c2 = v2[su].y - v0[su].y; sF32 ix = (v1[su].x - v0[su].x) * c2 + (v2[su].x - v0[su].x) * c1; if(sFAbs(ix) > 1e-20f) { ix = 1.0f / ix; t.Scale3(t1,c2*ix); t.AddScale3(t2,c1*ix); if(t.Dot3(t) > 1e-20f) { t.Unit3(); accu.Add3(t); } } } e = NextVertEdge(e); exit = e == ee || (Edge[e/2].Crease & msk); } while(!wasExit); if(ok) // write back { sVector *vd = VertBuf + i * vs; if(component == 0) // normal { accu.UnitSafe3(); vd[sn] = accu; } else // tangent { // remove component parallel to normal first accu.AddScale3(vd[sn],-accu.Dot3(vd[sn])); accu.UnitSafe3(); vd[st] = accu; } } } } } } void GenMesh::NeedAllNormals() { if(!GotNormals) { CalcNormals(0,7); GotNormals = sTRUE; } } /****************************************************************************/ void GenMesh::Triangulate(sInt threshold,sU32 dmask,sInt dmode,sInt type) { sInt i,j,c,v,e,ee; sInt Edgei[256]; sU32 Temp[256]; for(i=0;i=threshold) { switch(type) { case 0: { v = AddNewVert(); Vert[v].Sel(dmask,1,dmode); sVector *vd = VertBuf + v * VertSize(); sSetMem(vd,0,sizeof(sVector) * VertSize()); sF32 ic = 1.0f / c; for(j=0;jz < (VertBuf + Temp[start] * VertSize())->z) start = j; } if(start!=0) // lower deckel { for(j=start+3;j 1e-5f) // avoid precision problems { va = AddNewVert(); SplitBridge(NextVertEdge(i^1),PrevVertEdge(i^1),va,vb); t0 = -t0 / t1; for(j=0;jTemp[0] = GetVert(i)->Temp >= 0 && GetVert(i^1)->Temp >= 0; GetEdge(i)->Temp[1] = 0; } // fix faces noe = 0; for(i=0;iTemp[0]) // edge is on right side of plane? { if(pe==-1) { ee = e; force = sTRUE; } else if(pe!=PrevFaceEdge(e)) // need to add new edge { Edge.AtLeast(Edge.Count+1); Edge[Edge.Count].Init(); Edge[Edge.Count].Vert[0] = GetVertId(NextFaceEdge(pe)); Edge[Edge.Count].Vert[1] = GetVertId(e); Edge[Edge.Count].Next[0] = e; Edge[Edge.Count].Prev[0] = pe; Edge[Edge.Count].Face[0] = i; Edge[Edge.Count].Temp[0] = 0; Edge[Edge.Count].Temp[1] = 1; Edge[e/2].Prev[e&1] = Edge.Count*2; Edge[pe/2].Next[pe&1] = Edge.Count*2; e = Edge.Count*2; Edge.Count++; noe++; // number of open edges } Face[i].Edge = e; pe = e; ec++; } e = NextFaceEdge(e); } while(PrevFaceEdge(e) != ee || force); if(ec<3) { Face[i].Material=0; Face[i].Select=0; Face[i].Mask=0; } } // close mesh noet = noe; while(noe) { // find first open edge i = Edge.Count - noet; while(!Edge[i].Temp[1]) i++; sVERIFY(iTemp[1] = 0; sVERIFY(noe>0); noe--; for(i=(Edge.Count-noet)*2;iTemp[1] || i==ee) && Vert[GetVertId(i)].First==Vert[GetVertId(e^1)].First) break; } sVERIFY(i!=Edge.Count*2); Edge[e/2].Next[e&1]=i; Edge[i/2].Prev[i&1]=e; Edge[i/2].Face[i&1]=Face.Count-1; e=i; } while(e!=ee); } CleanupMesh(); } void GenMesh::CleanupMesh() { sInt i,j,fc,ec,e,ee; sInt *remape,*remapf; // cleanup faces and mark+renumber edges fc = 0; ec = 0; remape = new sInt[Edge.Count]; remapf = new sInt[Face.Count]; // prepare edges for(i=0;iData,bitmap->XSize,bitmap->YSize,0); sF32 xScale = bitmap->XSize * 65536.0f; sF32 yScale = bitmap->YSize * 65536.0f; sInt su = VertMap(sGMI_UV0); sInt sn = VertMap(sGMI_NORMAL); for(sInt i=0;iAddMul3(t0,amp); } } // restore fpu state __asm { fldcw [oldcw]; } } /****************************************************************************/ sBool GenMesh::Add(GenMesh *other,sInt not_useD_anymore) { sInt i,j,v,e,f,m,c,l,p; GenMeshVert *vp; GenMeshEdge *ep; GenMeshFace *fp; GenMeshMtrl *mm; GenMeshColl *cp; if(VertMask()!=other->VertMask()) return sFALSE; // make space for data v=Vert.Count; Vert.AtLeast(v+other->Vert.Count); Vert.Count+=other->Vert.Count; e=Edge.Count; Edge.AtLeast(e+other->Edge.Count); Edge.Count+=other->Edge.Count; f=Face.Count; Face.AtLeast(f+other->Face.Count); Face.Count+=other->Face.Count; m=Mtrl.Count; Mtrl.AtLeast(m+other->Mtrl.Count-1); //Mtrl.Count+=other->Mtrl.Count; c=Coll.Count; Coll.AtLeast(c+other->Coll.Count); Coll.Count+=other->Coll.Count; l=Lgts.Count; Lgts.AtLeast(l+other->Lgts.Count); Lgts.Count+=other->Lgts.Count; p=Parts.Count; Parts.AtLeast(p+other->Parts.Count); Parts.Count+=other->Parts.Count; Realloc(v+other->Vert.Count); // copy vertex info, reindex vertices for(i=0;iVert.Count;i++) { vp = &Vert[v+i]; *vp=other->Vert[i]; vp->Next+=v; vp->First+=v; vp->ReIndex+=v; } // copy edge indo, reindex edges for(i=0;iEdge.Count;i++) { ep = &Edge[e+i]; *ep = other->Edge[i]; for(j=0;j<2;j++) { ep->Next[j]+=e*2; ep->Prev[j]+=e*2; ep->Vert[j]+=v; ep->Face[j]+=f; } } // copy materials which are not unique other->Mtrl[0].Remap = 0; for(i=1;iMtrl.Count;i++) { for(j=1;jMtrl[i].Material && Mtrl[j].Pass == other->Mtrl[i].Pass) { other->Mtrl[i].Remap = j; goto nextmtrl; } } other->Mtrl[i].Remap = Mtrl.Count; mm = Mtrl.Add(); mm->Material = other->Mtrl[i].Material; if(mm->Material) mm->Material->AddRef(); mm->Pass = other->Mtrl[i].Pass; nextmtrl:; } // copy faces, reindex faces, assign new materials for(i=0;iFace.Count;i++) { fp = &Face[f+i]; *fp=other->Face[i]; fp->Edge+=e*2; fp->Material = other->Mtrl[fp->Material].Remap; } // copy collision for(i=0;iColl.Count;i++) { cp = &Coll[c+i]; for(j=0;j<8;j++) cp->Vert[j] = other->Coll[i].Vert[j]+v; cp->Mode = other->Coll[i].Mode; cp->Logic = other->Coll[i].Logic; } // copy lightslots for(i=0;iLgts.Count;i++) Lgts[l+i] = other->Lgts[i]+v; // copy parts for(i=0;iParts.Count;i++) Parts[p+i] = other->Parts[i]+f; // add vert buffers sCopyMem(VertBuf + v * VertSize(),other->VertBuf,other->Vert.Count * VertSize() * sizeof(sVector)); // a freshly added mesh doesn't have a pivot! Pivot = -1; UnPrepare(); return sTRUE; } /****************************************************************************/ void GenMesh::DeleteFaces() { sInt i; for(i=0;iSelect && !f->Temp && !fi->Select) { fi->Select = 1; fi->Temp = 1; } } } /****************************************************************************/ void GenMesh::CubicProjection(const sMatrix &mat,sInt mask,sInt dest,sBool real) { sInt i,j,bm,axis; sF32 max; sVector n; sMatrix matuv,matt; for(j=0;j<6;j++) { bm = real ? ((j & 1) ? 1 : -1) : 1; All2Sel(0,MAS_FACE|MAS_VERT); for(i=0;i sFAbs(max)) max = n.y, axis = 2; if(sFAbs(n.z) > sFAbs(max)) max = n.z, axis = 4; if(max>0.0f) axis++; // select appropriately Face[i].Select = axis == j; } else Face[i].Select = 0; } Crease(0,0,0,1<FromGenMesh(this); } #endif } /****************************************************************************/ void GenMesh::UnPrepare() { if(PreparedMesh) { PreparedMesh->Release(); PreparedMesh = 0; } #if !sPLAYER UnPrepareWire(); #endif } /****************************************************************************/ sBool GenMesh::Strip() { if(PreparedMesh) { Vert.Resize(0); Edge.Resize(0); Face.Resize(0); Coll.Resize(0); Compact(); VertCount = VertAlloc = 0; delete[] VertBuf; VertBuf = 0; Stripped = sTRUE; return sTRUE; } else return sFALSE; } sBool GenMesh::IsStripped() { return Stripped; } /****************************************************************************/ #if !sPLAYER void GenMesh::PrepareWire(sInt flags,sU32 selMask) { if(!WireMesh || WireFlags != flags || WireSelMask != selMask) { UnPrepareWire(); WireMesh = new EngMesh; WireMesh->FromGenMeshWire(this,flags,selMask); WireFlags = flags; WireSelMask = selMask; } } void GenMesh::UnPrepareWire() { if(WireMesh) { WireMesh->Release(); WireMesh = 0; } } #endif /****************************************************************************/ /*** ***/ /*** Commands ***/ /*** ***/ /****************************************************************************/ sBool CheckMesh(GenMesh *&mesh,sU32 mask) { GenMesh *oldmesh; if(mesh==0) return 1; if(mesh->ClassId!=KC_MESH) return 1; if(mesh->RefCount>1) { oldmesh = mesh; mesh = new GenMesh; mesh->Copy(oldmesh); oldmesh->Release(); } if(!(mask&0x80000000)) { if(mask) mesh->Mask2Sel(mask); else mesh->All2Sel(); } return 0; } /****************************************************************************/ /****************************************************************************/ GenMesh * __stdcall Mesh_Cube(sInt tx,sInt ty,sInt tz,sInt flags,sFSRT srt) { sInt i,j; sInt bm; sMatrix mat; sVector vc,vs,su; GenMesh *mesh; mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); mesh->Ring(4,0,1.4142135623730950488016887242097f/2,sPI2F/8); mesh->Face[0].Select = sTRUE; mesh->Extrude(0x00010000); mat.Init(); mat.l.z = 1; mesh->Mask2Sel(0x00010000); mesh->TransVert(mat); mat.l.Init(0.5f,0.5f,0.0,1.0f); mesh->All2Sel(); mesh->TransVert(mat); mat.Init(); mesh->TransVert(mat,sGMI_POS,sGMI_UV0); if(flags&8) // setup scale uv su.Init3(srt.s.x,srt.s.y,srt.s.z); else su.Init3(1,1,1); // extrude tesselation vc.Init(1,1,1,1); for(j=0;j<3;j++) { vs.Init(1025.0f,1025.0f,1025.0f,1); (&vs.x)[j] = 0.1f; mesh->SelectCube(vc,vs,0,0); mat.Init(); (&mat.l.x)[j] = 1.0f; for(i=1;i<(&tx)[j];i++) { mesh->Extrude(0x00010000,0x00000100); mesh->Face2Vert(); mesh->TransVert(mat); mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); } } // rescale t0 0.5 .. -0.5 mat.Init(); mat.i.x = 1.0f/tx; mat.j.y = 1.0f/ty; mat.k.z = 1.0f/tz; mesh->All2Sel(); mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); mat.l.Init(-0.5f,-0.5f,-0.5f,1); mesh->TransVert(mat); // mapping for(j=0;j<6;j++) { bm = ((j&1)?1:-1); vc.Init(0,0,0,1); vs.Init(1025,1025,1025,1); (&vc.x)[j/2] = bm*0.5f; (&vs.x)[j/2] = 0.001f; mesh->SelectCube(vc,vs,0,0); mesh->Crease(0,0,0,(flags&1) ? (sGMF_ALL & ~sGMF_POS) : sGMF_UV0); mesh->Face2Vert(); mesh->Sel2Mask((0x010100)<TransVert(mat,sGMI_POS,sGMI_UV0); } if(flags&2) // wraparound uv { // face 0 (left), then 4 (front), then 1, then 5. mat.Init(); mat.l.x = su.z; mesh->Mask2Sel(0x100000); mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); mat.l.x += su.x; mesh->Mask2Sel(0x020000); mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); mat.l.x += su.z; mesh->Mask2Sel(0x200000); mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); } // add collision #if sLINK_KKRIEGER if(flags&0x0030) { i = ((flags&0x0030)>>4)-1; i |= ((flags&0x00c0)>>4); mesh = Mesh_CollisionCube(mesh,0,0,-0.5f,0.5f,-0.5f,0.5f,-0.5f,0.5f,i,1,1,1); } #endif // transform the cube mesh->All2Sel(1); if(flags&4) // origin on bottom? { mat.Init(); mat.l.y = 0.5f; mesh->TransVert(mat); } mat.InitSRT(srt.v); mesh->TransVert(mat); // just one convex part, starting at face 0 *mesh->Parts.Add() = 0; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectAll(GenMesh *mesh,sU32 mask,sInt mode) { if(CheckMesh(mesh)) return 0; mesh->All2Mask(mask,mode); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectCube(GenMesh *mesh,sU32 dmask,sInt dmode,sF323 center,sF323 size) { if(CheckMesh(mesh)) return 0; size.x *= 0.5f; size.y *= 0.5f; size.z *= 0.5f; mesh->SelectCube((sVector&)center.x,(sVector&)size.x,0,0); if(dmode&4) mesh->Face2Vert(); mesh->Sel2Mask(dmask,dmode&3); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Subdivide(KOp *upd,GenMesh *mesh,sInt mask,sF32 alpha,sInt count) { if(CheckMesh(mesh,mask<<8)) return 0; while(count--) mesh->Subdivide(alpha); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Extrude(KOp *upd,GenMesh *mesh,sInt smask,sInt dmask,sInt mode,sInt count,sF323 dist,sF323 s,sF323 r) { sInt i,j,grp,e,ee; static sInt stk[4096]; sMatrix mat; if(CheckMesh(mesh,smask<<8)) return 0; mesh->NeedAllNormals(); grp = ((mode & 8) || ((mode & 6) == 2)) ? 0 : 1; // first, classify faces for(i=0;iFace.Count;i++) mesh->Face[i].Temp = grp - 1; while(1) { for(i=0;iFace.Count;i++) { if(mesh->Face[i].Temp==-1 && mesh->Face[i].Select) break; } if(i==mesh->Face.Count) break; stk[0] = i; j = 1; while(j) { i = stk[--j]; mesh->Face[i].Temp = grp; e = ee = mesh->Face[i].Edge; do { i = mesh->GetFaceId(e^1); if(mesh->Face[i].Temp==-1 && !mesh->IsBorderEdge(e,mode&1)) { mesh->Face[i].Temp = -2; stk[j++] = i; } e = mesh->NextFaceEdge(e); } while(e!=ee); } grp++; } // scale transform parameters sF32 ic = 1.0f / count; for(i=0;i<3;i++) { s[i] = sFPow(sFAbs(s[i]),ic) * (s[i] < 0 ? -1.0f : 1.0f); r[i] = r[i] * ic; dist[i] = dist[i] * ic; } mat.InitEulerPI2(&r.x); sInt vs = mesh->VertSize(); sInt sn = mesh->VertMap(sGMI_NORMAL); if(((mode>>4)&3)>=MSM_SET) // selection mode is "set"? mesh->All2Mask((dmask & 0xff)<<8,MSM_SUB); // clear target selection sVector n,p; if((mode & 6) == 4) // direction n.Init(dist.x,dist.y,dist.z,0); // main loop while(count--) { mesh->Extrude((dmask & 0xff)<<8,(mode>>4)&3,mode&1); for(i=0;iVert.Count;i++) mesh->Vert[i].Temp = 0; sInt vcount; for(i=0;iFace.Count-1;j>=0;j--) { GenMeshFace *face = &mesh->Face[j]; if(face->Select && face->Temp == i) { face->Temp2 = ffirst; ffirst = j; } } // first pass: face to vertex normals (if required) if((mode&6)==6) // face normals { //for(sInt f=0;fFace.Count;f++) for(sInt f=ffirst;f!=-1;f=mesh->Face[f].Temp2) { GenMeshFace *face = &mesh->Face[f]; if(face->Select && face->Temp == i) { sVector normal; mesh->CalcFaceNormal(normal,face->Edge); normal.UnitSafe3(); e = ee = face->Edge; do { mesh->VertBuf[mesh->GetVertId(e) * vs + sn] = normal; e = mesh->NextFaceEdge(e); } while(e != ee); } } } // second pass: find average normal (if required) // third pass: vertex displacement and summing // fourth pass: local scale (if required) for(sInt pass=1;pass<4;pass++) { sInt passMask = 1 << pass; if(pass == 1) { if((mode & 6) != 2) continue; n.Init(0,0,0,0); } else if(pass == 2) { if((mode & 6) == 2) { n.UnitSafe3(); n.Mul3((sVector&) dist); } p.Init(0,0,0,1); } else if(pass == 3) { if(!(mode & 8)) continue; p.Scale3(1.0f / vcount); } vcount = 0; //for(sInt f=0;fFace.Count;f++) for(sInt f=ffirst;f!=-1;f=mesh->Face[f].Temp2) { GenMeshFace *face = &mesh->Face[f]; if(face->Select && face->Temp == i) { e = ee = face->Edge; do { GenMeshVert *vert = mesh->GetVert(e); if(vert->Temp & passMask) { e = mesh->NextFaceEdge(e); continue; } vert->Temp |= passMask; sInt v = mesh->GetVertId(e); sVector *vd = mesh->VertBuf + v * vs; if(pass == 1) n.Add3(vd[sn]); else if(pass == 2) { if((mode & 6) == 0 || (mode & 6) == 6) // indiv./face normal vd->AddMul3(vd[sn],(sVector&) dist); else vd->Add3(n); if(mode & 8) p.Add3(*vd); else { vd->Mul3((sVector&) s); vd->Rotate3(mat); } vd[sn].Rotate3(mat); } else if(pass == 3) { sVector t; // MODIFIED BEHAVIOR!!! t.x = (vd->x - p.x) * s.x; t.y = (vd->y - p.y) * s.y; t.z = (vd->z - p.z) * s.z; vd->Rotate34(mat,t); vd->x += p.x; vd->y += p.y; vd->z += p.z; } vcount++; e = mesh->NextFaceEdge(e); } while(e != ee); } } } } } if(dmask&0xff) mesh->Mask2Sel((dmask & 0xff)<<8); mesh->Face2Vert(); mesh->Sel2Mask((dmask & 0xff00)<<8); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Transform(KOp *upd,GenMesh *mesh,sInt mask,sFSRT srt) { sMatrix mat; if(CheckMesh(mesh,mask<<16)) return 0; mat.InitSRT(srt.v); #if !sINTRO if(mesh->Pivot!=-1) mat.PivotTransform(mesh->VertBuf[mesh->Pivot*mesh->VertSize()]); #endif mesh->TransVert(mat); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_TransformEx(KOp *upd,GenMesh *mesh,sInt mask,sFSRT srt,sInt sj,sInt dj) { sMatrix mat; if(CheckMesh(mesh,mask<<16)) return 0; if(sj == sGMI_NORMAL || sj == sGMI_TANGENT) mesh->NeedAllNormals(); mat.InitSRT(srt.v); #if !sINTRO if(mesh->Pivot!=-1 && mesh->VertMap(sj)!=-1) mat.PivotTransform(mesh->VertBuf[mesh->Pivot*mesh->VertSize()+mesh->VertMap(sj)]); #endif mesh->TransVert(mat,sj,dj); if(dj == sGMI_POS || dj == sGMI_NORMAL || dj == sGMI_TANGENT) mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Cylinder(sInt tx,sInt ty,sInt mode,sInt tz,sInt arc) { sInt i,sj,e; sMatrix mat,matuv; sVector vc,vs; GenMesh *mesh; arc = sRange(arc,tx-1,0); mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); // create cylinder mesh->Ring(tx,0,0.5f,0,arc); mat.Init(); mat.l.z = 1; matuv.Init(); matuv.l.y = 1.0f/ty; mesh->Face[0].Select = sTRUE; for(i=0;iEdge.Count; mesh->Extrude(0); mesh->Edge[e].Sel(0x000001,1,MSM_ADD); mesh->Face2Vert(); mesh->TransVert(mat); mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } // adjust size static const sF32 turn[] = { 0.25,0.0f,0.0f }; mat.InitEulerPI2(turn); vs.Init(1.0f/tz,1.0f/ty,1.0f/tz,1.0f); mat.i.Mul4(vs); mat.j.Mul4(vs); mat.k.Mul4(vs); mat.l.Init(0,0.5f,0.0f,1); mesh->All2Sel(1,MAS_VERT); mesh->TransVert(mat); // make selection & caps mesh->All2Mask(0x010100,MSM_SUB); vc.Init(); vs.Init(1025.0f,0.0001f,1025.0f,0.0f); vc.y = 0.5f; mesh->SelectCube(vc,vs,0x010100,MSM_ADD); vc.y = -0.5f; mesh->SelectCube(vc,vs,0x010100,MSM_ADD); mesh->Mask2Sel(0x100); mesh->Triangulate(4,0,0,(arc>0)?2:0); // extrude rings if(tz>1) { mesh->All2Sel(1,MAS_VERT); mat.Init(); mat.j.y = 0.0f; mesh->TransVert(mat,sGMI_POS,sGMI_NORMAL); mesh->Mask2Sel(0x100); for(i=0;iFace.Count;i++) mesh->Face[i].Select ^= 1; for(i=1;iEdge.Count; mesh->Extrude(0x100,MSM_ADD); while(eEdge.Count) mesh->Edge[e++].Mask=0; mesh->Face2Vert(); mesh->ExtrudeNormal(1.0f); } } // correct mapping sj = mesh->VertMap(sGMI_UV0); if(sj!=-1) { for(i=-1;i<2;i+=2) { vs.Init(2,0.01f,2,1); vc.Init(0,i*0.5f,0,1); mesh->All2Sel(0,MAS_FACE|MAS_VERT); mesh->SelectCube(vc,vs,0,0); mesh->Crease(); mesh->Face2Vert(); matuv.Init(); matuv.j.y = 0.0f; matuv.k.y = -i; matuv.l.Init(0.5f,0.5f,0,1); mesh->TransVert(matuv,sGMI_POS,sGMI_UV0); } mesh->All2Mask(0x020000,MSM_SUB); mesh->Mask2Sel(0x020001); mesh->Crease(1,0,0,sGMF_UV0); // uv0 only mesh->Edge2Vert(0); matuv.Init(); matuv.l.x = 1.0f; mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } if(mode&1) mesh = Mesh_DeleteFaces(mesh,0x01); if(mode&2) // origin on bottom? { mat.Init(); mat.l.y = 0.5f; mesh->All2Sel(1); mesh->TransVert(mat); } mesh->All2Mask(1,MSM_SUB); // just one convex part, starting at face 0 *mesh->Parts.Add() = 0; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Crease(GenMesh *mesh,sInt mask,sInt what,sInt selType) { if(CheckMesh(mesh,mask<<(selType ? 0 : 8))) return 0; mesh->Crease(selType,0,0,1<<(what+1)); mesh->Face2Vert(); mesh->Sel2Mask(mask<<16,MSM_SET); if(what & (sGMF_NORMAL | sGMF_TANGENT)) mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_UnCrease(GenMesh *mesh,sInt mask,sInt what,sInt selType) { SCRIPTVERIFY(what); if(CheckMesh(mesh,mask<<8)) return 0; mesh->UnCrease(selType,1<<(what+1)); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_CalcNormals(GenMesh *mesh,sInt mode,sInt mask,sInt what) { if(CheckMesh(mesh,mask<<8)) return 0; mesh->CalcNormals(mode,what); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Torus(sInt tx,sInt ty,sF32 ro,sF32 ri,sF32 phase,sF32 arclen,sInt flags) { sInt i,n,e,f,t; sInt sj; sBool closed; sMatrix mat,matuv; GenMesh *mesh; mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); closed = arclen == 1.0f; if(flags&1) // absolute radii { ri = (ro - ri) * 0.5f; ro -= ri; } // create torus mesh->Ring(ty,0,ri,phase*sPI2/ty); mat.Init(); mat.l.x = -ro; mesh->Face[0].Select = sTRUE; mesh->Face2Vert(); mesh->TransVert(mat); mat.InitEuler(0.0f,arclen*sPI2/tx,0.0f); matuv.Init(); matuv.l.y = 1.0f/tx; for(i=0;iEdge.Count; mesh->Extrude(0); mesh->Edge[e].Sel(0x000001,1,MSM_ADD); mesh->Face2Vert(); mesh->TransVert(mat); mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } // that was easy... now we need to merge start and end faces! if(closed) { // delete the start/end faces mesh->Face[1].Select = sTRUE; mesh->DeleteFaces(); e = mesh->Edge.Count; f = mesh->Face.Count; mesh->Edge.AtLeast(e+ty); mesh->Edge.Count+=ty; mesh->Face.AtLeast(f+ty); mesh->Face.Count+=ty; // make the new edges for(i=0;iEdge[e+i].Init(); mesh->Edge[e+i].Vert[0] = mesh->Vert.Count-ty+i; mesh->Edge[e+i].Vert[1] = i; } mesh->Edge[e].Sel(0x000001,1,MSM_ADD); // make the faces (and mark the v crease while we're at it) for(i=0;iNextFaceEdge(mesh->Face[2+i].Edge)^1; mesh->MakeFace(f+i,4,t,(e+i)*2+1,mesh->PrevFaceEdge(mesh->Face[f-ty+i].Edge)^1,(e+n)*2); mesh->Edge[t/2].Sel(0x000002,1,MSM_ADD); } } // prepare the creases sj = mesh->VertMap(sGMI_UV0); if(sj!=-1) { if(!closed) { mesh->All2Sel(0,MAS_FACE); mesh->Face[0].Select = 1; mesh->Face[1].Select = 1; mesh->Crease(0,0,0,sGMF_UV0); // perform uv projection at caps } for(i=0;i<2;i++) { mesh->All2Mask(0x010000,MSM_SUB); mesh->Mask2Sel((i+1)|0x010000); mesh->Crease(1,0,0,sGMF_UV0); matuv.Init(); (&matuv.l.x)[i] = 1.0f; mesh->Edge2Vert(i); mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } } // origin on bottom? if(flags&2) { mat.Init(); mat.l.y = ri; mesh->All2Sel(1); mesh->TransVert(mat); } // just one closed part, starting at face 0 *mesh->Parts.Add() = 0; mesh->All2Mask(~0,MSM_SETNOT); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Sphere(sInt tx,sInt ty) { sInt i,j,v,sj; sMatrix mat,matuv; GenMesh *mesh; mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); // first, generate a cheesy cylinder matuv.Init(); matuv.l.y = 1.0f / ty; mesh->Ring(tx,0,0.5f,0.0f); mesh->Face[mesh->Face.Count-1].Select = sTRUE; for(i=0;iExtrude(0); mesh->Face2Vert(); mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } matuv.j.y = -1.0f; matuv.l.y = 1.0f; mesh->All2Sel(1,MAS_VERT); mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); // swap axes mat.Init(); mat.j.y = 0.0f; mat.j.z = 1.0f; mat.k.y = 1.0f; mat.k.z = 0.0f; mesh->All2Sel(1,MAS_VERT); mesh->TransVert(mat); // make it a sphere v=mesh->Vert.Count-tx*(ty+1); for(i=0;i<=ty;i++) { mesh->All2Sel(0,MAS_VERT); for(j=0;jVert[v].Select=1; mat.Init(); mat.i.x = mat.k.z = sFSin((i+0.5f)*sPI/(ty+1)); mat.l.y = -0.5f*sFCos((i+0.5f)*sPI/(ty+1)); mesh->TransVert(mat); } // fix top/bottom for(i=0;i<2;i++) { mesh->All2Sel(0,MAS_FACE); mesh->Face[i].Select=1; mesh->Face[i].Sel(0x000100,1,MSM_ADD); mesh->Triangulate(4,0x000100); } // make the u-crease sj=mesh->VertMap(sGMI_UV0); if(sj!=-1) { mesh->All2Sel(0,MAS_VERT); mesh->VertBuf[(mesh->Vert.Count-2)*mesh->VertSize()+sj].x=0; mesh->VertBuf[(mesh->Vert.Count-1)*mesh->VertSize()+sj].x=0; for(i=0;iEdge.Count;i++) { if(mesh->VertBuf[mesh->GetVertId(i*2+0)*mesh->VertSize()+sj].x==0 && mesh->VertBuf[mesh->GetVertId(i*2+1)*mesh->VertSize()+sj].x==0) { mesh->Edge[i].Select=1; } else mesh->Edge[i].Select=0; } mesh->Crease(1,0,0,sGMF_UV0); // uv0 only mesh->Edge2Vert(0); mesh->Vert[0].Select=0; matuv.Init(); matuv.l.x = 1.0f; mesh->TransVert(matuv,sGMI_UV0,sGMI_UV0); } // just one closed part, starting at face 0 *mesh->Parts.Add() = 0; mesh->All2Mask(0xfffeff,MSM_SUB); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Triangulate(GenMesh *mesh,sInt mask,sInt thres,sInt type) { if(CheckMesh(mesh,mask<<8)) return 0; mesh->Triangulate(thres,0,0,type); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Cut(GenMesh *mesh,sF322 dir,sF32 offs,sInt mode) { sMatrix mat; sVector plane; if(CheckMesh(mesh)) return 0; mat.InitEuler(dir.x*sPI2F,dir.y*sPI2F,0.0f); plane.Init4(mat.i.x,mat.j.x,mat.k.x,offs); mesh->All2Sel(); mesh->Cut(plane,mode); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_ExtrudeNormal(KOp *upd,GenMesh *mesh,sInt mask,sF32 distance) { if(CheckMesh(mesh,mask<<16)) return 0; mesh->NeedAllNormals(); mesh->ExtrudeNormal(distance); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Displace(KOp *upd,GenMesh *mesh,GenBitmap *bmp,sInt mask,sF323 ampli) { SCRIPTVERIFY(bmp); if(CheckMesh(mesh,mask<<16)) return 0; mesh->NeedAllNormals(); mesh->Displace(bmp,ampli.x,ampli.y,ampli.z); bmp->Release(); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Bevel(KOp *upd,GenMesh *mesh,sInt mask,sF32 elev,sF32 pull,sInt mode) { if(CheckMesh(mesh,mask<<8)) return 0; mesh->NeedAllNormals(); mesh->Bevel(elev,pull,mode,0,mask<<8); mesh->GotNormals = sFALSE; //mesh->Sel2Mask(dmask<<16,0); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Perlin(KOp *upd,GenMesh *mesh,sInt mask,sFSRT srt,sF323 ampl) { sMatrix mat; if(CheckMesh(mesh,mask<<16)) return 0; mat.InitSRT(srt.v); mesh->Perlin(mat,(sVector&) ampl.x); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Add(sInt count,GenMesh *mesh,...) { sInt i; GenMesh *other; if(CheckMesh(mesh)) return 0; for(i=1;iAdd(other); other->Release(); } } mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_DeleteFaces(GenMesh *mesh,sInt mask) { if(CheckMesh(mesh,mask<<8)) return 0; mesh->DeleteFaces(); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_BeginRecord(GenMesh *mesh) { return mesh; /* SCRIPTVERIFY(mesh); if(CheckMesh(mesh)) return 0; mesh->RecStoreMode(); return mesh;*/ } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectRandom(GenMesh *mesh,sU32 dmask,sInt dmode,sU32 ratio,sInt seed) { sInt i; if(CheckMesh(mesh)) return 0; sSetRndSeed(seed+seed*31743^(seed<<23)); for(i=0;iEdge.Count;i++) mesh->Edge[i].Select=(sGetRnd()>>24)<=ratio; for(i=0;iVert.Count;i++) mesh->Vert[i].Select=(sGetRnd()>>24)<=ratio; for(i=0;iVert.Count;i++) mesh->Vert[i].Select=mesh->Vert[mesh->Vert[i].First].Select; for(i=0;iFace.Count;i++) mesh->Face[i].Select=(sGetRnd()>>24)<=ratio && mesh->Face[i].Material; mesh->Sel2Mask(dmask,dmode); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Multiply(KOp *kop,GenMesh *mesh,sFSRT srt,sInt count,sInt mode,sF32 tu,sF32 tv,sF323 lrot,sF32 extrude) { sInt i,j; GenMesh *out; sMatrix xform,step,lxform,lstep,tmp; if(CheckMesh(mesh)) return 0; step.InitSRT(srt.v); lstep.InitEulerPI2(&lrot.x); out = new GenMesh; out->Init(mesh->VertMask(),0); xform.Init(); lxform.Init(); if(extrude) mesh->NeedAllNormals(); sSetRndSeed(count); for(j=0;jAdd(mesh,!!j); // 0:not keepmaterial: 1..n keepmaterial for(i=0;iVert.Count-mesh->Vert.Count;i++) out->Vert[i].Select=0; while(iVert.Count) out->Vert[i++].Select=1; if(extrude) { tmp.Init(); tmp.i.x = j*extrude; tmp.j.y = j*extrude; tmp.k.z = j*extrude; out->TransVert(tmp,sGMI_NORMAL,sGMI_POS | 0x10); } tmp.MulA(lxform,xform); out->TransVert(tmp); if(mode&2) xform.InitRandomSRT(srt.v); else xform.MulA(step); lxform.MulA(lstep); if(mode&1) { tmp.Init(); tmp.l.x = j*tu; tmp.l.y = j*tv; out->TransVert(tmp,sGMI_UV0,sGMI_UV0); } } mesh->Release(); out->GotNormals = sFALSE; return out; } /****************************************************************************/ /*GenMesh * __stdcall Mesh_SelectAngle(GenMesh *mesh,sF32 angle,sU32 dmask1,sU32 dmask0) { sInt i; sVector f0,f1; if(CheckMesh(mesh)) return 0; angle = cos(angle*sPI2F*0.25f); for(i=0;iEdge.Count;i++) { mesh->CalcFaceNormal(f0,i*2 ); f0.UnitSafe3(); mesh->CalcFaceNormal(f1,i*2+1); f1.UnitSafe3(); if(sFAbs(f0.Dot3(f1))Edge[i].Sel(dmask1,dmask0); } return mesh; }*/ /****************************************************************************/ GenMesh * __stdcall Mesh_Bend(KOp *upd,GenMesh *mesh,sInt mask,sFSRT srt1,sFSRT srt2,sF322 dir,sF322 yrange,sInt mode) { sMatrix mat1,mat2,matt; if(CheckMesh(mesh,mask<<16)) return 0; mat1.InitSRT(srt1.v); #if !sINTRO if(mesh->Pivot!=-1) mat1.PivotTransform(mesh->VertBuf[mesh->Pivot*mesh->VertSize()]); #endif mat2.InitSRT(srt2.v); #if !sINTRO if(mesh->Pivot!=-1) mat2.PivotTransform(mesh->VertBuf[mesh->Pivot*mesh->VertSize()]); #endif matt.InitEuler(dir.x*sPI2F,0.0f,dir.y*sPI2F); // first pass: find min/max (transformed) y coordinate (if necessary) sF32 ymin,ymax; if(mode & 2) { ymin = 1e+30f; ymax = -1e+30f; for(sInt i=0;iVert.Count;i++) { if(mesh->Vert[i].Select) { sVector *v = mesh->VertBuf + i * mesh->VertSize(); sF32 t = v->x*matt.i.y + v->y*matt.j.y + v->z*matt.k.y; ymin = sMin(ymin,t); ymax = sMax(ymax,t); } } } else { ymin = yrange.x; ymax = yrange.y; } sF32 yscale = 1.0f / (ymax - ymin); for(sInt i=0;iVert.Count;i++) { if(mesh->Vert[i].Select) { sVector *v = mesh->VertBuf + i * mesh->VertSize(); sF32 t = (v->x*matt.i.y + v->y*matt.j.y + v->z*matt.k.y - ymin) * yscale; t = sRange(t,1.0f,0.0f); switch(mode & 5) { case 1: t = t * t * (3.0f - 2.0f * t); break; case 4: t = 1.0f - fabs(t - 0.5f) * 2.0f; break; case 5: t = t * t * (16.0f + t * (16.0f * t - 32.0f)); break; } sVector v1,v2; v1.Rotate34(mat1,*v); v2.Rotate34(mat2,*v); v->Lin3(v1,v2,t); } } return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_CollisionCube(GenMesh *input,KOp *event,KOp *event2,sF32 x0,sF32 x1,sF32 y0,sF32 y1,sF32 z0,sF32 z1,sInt mode,sInt tx,sInt ty,sInt tz,sInt eventa,sInt eventb,sInt eventc,sInt eventd) { GenMesh *mesh; sInt i,ix,iy,iz,max,count,index; sF32 phi[2]; sVector *v; sVector v0,vs; if(input && CheckMesh(input,0)) return 0; #if !sPLAYER if((mode&3)==3) sDPrintF("oops\n"); #endif if((mode&16) && tz<3) tz = 3; max = tx*ty*tz; sVERIFY(max>0); mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,max*8); mesh->Coll.AtLeast(max); mesh->Coll.Count = max; v0.w = 1; vs.x = x0-x1; vs.y = y0-y1; vs.z = z0-z1; vs.w = 0; if(!(mode&16)) { v0.x = x1; v0.y = y1; v0.z = z1; vs.x /= tx; vs.y /= ty; vs.z /= tz; } else { v0.x = (x0+x1)*0.5f; v0.y = y0; v0.z = (z0+z1)*0.5f; vs.x /= -tx*2.0f; vs.y /= -ty; vs.z /= -tx*2.0f; } count = 0; for(ix=0;ixColl[count].Mode = mode&15; mesh->Coll[count].Logic.Code = eventa; mesh->Coll[count].Logic.Condition = eventb; mesh->Coll[count].Logic.Value = eventc; mesh->Coll[count].Logic.Output = eventd; mesh->Coll[count].Logic.Event[0] = event; mesh->Coll[count].Logic.Event[1] = event2; phi[0] = (iz+1)*sPI2F/tz; phi[1] = (iz+0)*sPI2F/tz; for(i=0;i<8;i++) { index = mesh->AddNewVert(); mesh->Coll[count].Vert[i] = index; v = mesh->VertBuf + index * mesh->VertSize(); if(mode&16) { v->x = v0.x + sFSin(phi[i&1])*vs.x*(ix+((i>>2)&1)); v->y = v0.y + vs.y*(iy+((i>>1)&1)); v->z = v0.z + sFCos(phi[i&1])*vs.z*(ix+((i>>2)&1)); } else { v->x = v0.x + vs.x*(ix+((i>>0)&1)); v->y = v0.y + vs.y*(iy+((i>>1)&1)); v->z = v0.z + vs.z*(iz+((i>>2)&1)); } v->w = 1.0; } count++; } } } sVERIFY(count==max); if(input) { input->Add(mesh); mesh->Release(); return input; } else { return mesh; } } /****************************************************************************/ static void MultiSplit(GenMesh *mesh,sInt e,sInt splits) { sInt va,vb,va0,va1,vb0,vb1,vs; sInt i,j; sF32 t; va0 = mesh->GetVertId(e); va1 = mesh->GetVertId(mesh->NextFaceEdge(e)); vb0 = mesh->GetVertId(mesh->NextFaceEdge(e^1)); vb1 = mesh->GetVertId(e^1); vs = mesh->VertSize(); for(i=0;iAddNewVert(); mesh->SplitBridge(mesh->NextVertEdge(e^1),mesh->PrevVertEdge(e^1),va,vb); for(j=0;jVertBuf[va*vs+j].Lin4(mesh->VertBuf[va0*vs+j],mesh->VertBuf[va1*vs+j],t); mesh->VertBuf[vb*vs+j].Lin4(mesh->VertBuf[vb0*vs+j],mesh->VertBuf[vb1*vs+j],t); } e = mesh->NextFaceEdge(e); mesh->Edge[e/2].Select = 1; } } static void QuadSplit(GenMesh *mesh,sInt e,sInt splits,sInt offs,sInt offt) { sInt e1,e2; if(!splits) return; e1 = mesh->SkipFaceEdge(e,offs); e2 = mesh->SkipFaceEdge(e1,2); if(!mesh->Edge[e1/2].Select) { mesh->Edge[e1/2].Select = 1; MultiSplit(mesh,e1,splits); } if(!mesh->Edge[e2/2].Select) { mesh->Edge[e2/2].Select = 1; MultiSplit(mesh,e2,splits); } while(splits--) { e2 = mesh->SkipFaceEdge(e,offt+1); mesh->SplitFace(e2,mesh->SkipFaceEdge(e2,-3)); e = mesh->SkipFaceEdge(e2,-offt); } } GenMesh * __stdcall Mesh_Grid(sInt mode,sInt tesu,sInt tesv) { GenMesh *mesh; sMatrix mat; sInt i,j; sVector *v,t; mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,4); mesh->Ring(4,0,1.4142135623730950488016887242097f/2,sPI2F/8); // make crease mesh->All2Sel(); mesh->Face[1].Select = 0; mesh->Crease(); mesh->Face[1].Select = 1; mat.Init(); mat.j.y = -1.0f; mat.l.x = 0.5f; mat.l.y = 0.5f; mesh->TransVert(mat,sGMI_POS,sGMI_UV0); mat.InitEuler(0.25f*sPI2F,0.0f,0.0f); mesh->TransVert(mat); mesh->CalcNormals(); for(i=0;iVert.Count;i++) { v = mesh->VertBuf + i * mesh->VertSize(); if(v[1].y < 0.0f) { v += mesh->VertMap(sGMI_UV0); v->x = 1.0f - v->x; } } // split vertical mesh->All2Sel(0); QuadSplit(mesh,mesh->Face[0].Edge,tesv-1,0,0); QuadSplit(mesh,mesh->Face[1].Edge,tesv-1,0,2); // split horizontal mesh->All2Sel(0); for(i=0;iFace[i].Edge,tesu-1,-1,1); // selection: side 1/2 mesh->All2Mask(~0,MSM_SETNOT); mesh->All2Sel(0); for(i=0;iFace.Count;i++) mesh->Face[i].Select = mesh->VertNorm(mesh->GetVertId(mesh->Face[i].Edge)).y<0.0f; mesh->Face2Vert(); mesh->Sel2Mask(0x010100,MSM_SET); mesh = Mesh_SelectLogic(mesh,0x010100,0x010100,0x020200,19); // selection: outer x/z for(i=0;i<=2;i+=2) { mesh->All2Sel(0); for(j=0;jEdge.Count*2;j++) { if(mesh->Edge[j/2].Crease) { t.Sub3(mesh->VertPos(mesh->GetVertId(j)),mesh->VertPos(mesh->GetVertId(j^1))); if(sFAbs((&t.x)[i]) > 1e-6f) mesh->GetFace(j)->Select = 1; } } mesh->Face2Vert(); mesh->Sel2Mask(0x040400 << i,MSM_SET); mesh = Mesh_SelectLogic(mesh,0x040400<Parts.Add() = 0; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectLogic(GenMesh *msh,sU32 smask1,sU32 smask2,sU32 dmask,sInt mode) { sInt i; sU32 smask; // sBool s1,s2; if(CheckMesh(msh)) return 0; smask = smask1 | smask2; if((smask & 0x0000ff) && (dmask & 0x0000ff)) { for(i=0;iEdge.Count;i++) msh->Edge[i].SelLogic(smask1,smask2,dmask,mode & 31); } if((smask & 0x00ff00) && (dmask & 0x00ff00)) { for(i=0;iFace.Count;i++) msh->Face[i].SelLogic(smask1>>8,smask2>>8,dmask>>8,mode & 31); } if((smask & 0xff0000) && (dmask & 0xff0000)) { for(i=0;iVert.Count;i++) msh->Vert[i].SelLogic(smask1>>16,smask2>>16,dmask>>16,mode & 31); } if((dmask & 0xff0000) && (dmask & 0x00ff00) && (mode & 32)) { msh->Mask2Sel(dmask & 0x00ff00); msh->Face2Vert(); msh->Sel2Mask(dmask & 0xff0000,MSM_SET); } return msh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectGrow(GenMesh *msh,sU32 smask,sU32 dmask,sInt dmode,sInt amount) { if(CheckMesh(msh,smask<<8)) return 0; while(amount--) msh->SelectGrow(); msh->Face2Vert(); msh->Sel2Mask(dmask<<8,dmode); return msh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Invert(GenMesh *msh) { sInt i; GenMeshEdge *edg; // GenMeshColl *coll; if(CheckMesh(msh)) return 0; for(i=0;iEdge.Count;i++) { edg = &msh->Edge[i]; edg->Temp[0] = msh->GetVertId(edg->Next[0]); edg->Temp[1] = msh->GetVertId(edg->Next[1]); } for(i=0;iEdge.Count;i++) { edg = &msh->Edge[i]; sSwap(edg->Next[0],edg->Prev[0]); sSwap(edg->Next[1],edg->Prev[1]); edg->Vert[0] = edg->Temp[0]; edg->Vert[1] = edg->Temp[1]; } msh->GotNormals = sFALSE; return msh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SetPivot(GenMesh *msh,sInt attr,sF323 pivot) { sInt j; if(CheckMesh(msh)) return 0; j = msh->VertMap(attr); if(j!=-1) msh->VertBuf[msh->AddPivot()*msh->VertSize()+j].Init(pivot.x,pivot.y,pivot.z,1.0f); return msh; } /****************************************************************************/ GenMesh * __stdcall Mesh_UVProjection(GenMesh *msh,sInt mask,sFSRT srt,sInt type) { sInt i,sj; sVector n,*v0; sMatrix mat; //sInt sv,ind; //sVector *v1; //sF32 d; if(CheckMesh(msh)) return 0; mat.InitSRT(srt.v); if(!type || type == 3) // cubic projection mapping msh->CubicProjection(mat,mask,sGMI_UV0,type == 0); else // spherical or cylindrical projection { sj = msh->VertMap(sGMI_UV0); // make initial mapping /*for(i=0;iVert.Count;i++) msh->Vert[i].Temp = 0;*/ for(i=0;iVert.Count;i++) { // get transformed source pos v0 = msh->VertBuf + i * msh->VertSize(); n.Rotate34(mat,v0[0]); /*if(sFAbs(n.x) < 1e-6f) n.x = 0.0f; if(sFAbs(n.z) < 1e-6f) n.z = 0.0f;*/ sF32 xzd = n.x*n.x+n.z*n.z; v0[sj].x = 0.5f-sFATan2(n.x,n.z)/sPI2F; if(type==1) // cylindrical v0[sj].y = -n.y; else v0[sj].y = 0.5f-sFATan2(n.y,sFSqrt(xzd))/sPIF; /*// tag poles as singular if(n.y / sFAbs(xzd) > 1e+6f) { msh->Vert[msh->Vert[i].First].Temp = 2; msh->Vert[i].Temp = 2; }*/ } /* // tag singular verts for(i=0;iEdge.Count*2;i++) { v0 = msh->VertBuf + msh->GetVertId(i) * msh->VertSize(); v1 = msh->VertBuf + msh->GetVertId(i^1) * msh->VertSize(); d = -(v0[sj].x - v1[sj].x); if(d >= 0.5f) // singular edge { sv = msh->GetVertId(i); if(msh->Vert[msh->GetVert(i^1)->First].Temp != 2) { // tag vert as singular msh->Vert[msh->Vert[sv].First].Temp = 1; msh->Vert[sv].Temp = 1; msh->Edge[i/2].Temp[0] = i; } else msh->Edge[i/2].Temp[0] = -1; } else if(d > -0.5f) msh->Edge[i/2].Temp[0] = -1; } // tag crease edges for(i=0;iEdge.Count;i++) { msh->Edge[i].Select = msh->Vert[msh->GetVert(i*2)->First].Temp && msh->Vert[msh->GetVert(i*2+1)->First].Temp; } // make uv creases msh->Crease(1,0,0,sGMF_UV0); // adjust UVs for(i=0;iEdge.Count;i++) { ind = msh->Edge[i].Temp[0]; if(ind != -1) // singular edge { if(msh->GetVert(ind)->Temp) // still singular vert { v0 = msh->VertBuf + msh->GetVertId(ind) * msh->VertSize(); v0[sj].x += 1.0f; msh->GetVert(ind)->Temp = 0; } } }*/ } return msh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Center(GenMesh *mesh,sInt mask,sInt which) { sMatrix mat; sAABox box; if(CheckMesh(mesh,mask<<16)) return 0; mesh->CalcBBox(box); mesh->All2Sel(1,MAS_VERT); mat.Init(); if(which&1) mat.l.x = -0.5f * (box.Min.x + box.Max.x); if(which&2) mat.l.y = (which & 128) ? -box.Min.y : -0.5f * (box.Min.y + box.Max.y); if(which&4) mat.l.z = -0.5f * (box.Min.z + box.Max.z); mesh->TransVert(mat); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_AutoCollision(GenMesh *mesh,sF32 enlarge,sInt mode,sInt tx,sInt ty,sInt tz,sInt outmask) { sAABox box; GenMesh *coll; if(CheckMesh(mesh)) return 0; mesh->CalcBBox(box); coll = Mesh_CollisionCube(0,0,0,box.Min.x-enlarge,box.Max.x+enlarge, box.Min.y-enlarge,box.Max.y+enlarge,box.Min.z-enlarge,box.Max.z+enlarge,mode,tx,ty,tz); mesh->All2Mask(outmask<<16,MSM_SETNOT); coll->All2Mask(outmask<<16,MSM_SET); mesh->Add(coll); coll->Release(); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectSphere(GenMesh *mesh,sU32 dmask,sInt dmode,sF323 center,sF323 size) { if(CheckMesh(mesh)) return 0; size.x *= 0.5f; size.y *= 0.5f; size.z *= 0.5f; mesh->SelectSphere((sVector&)center.x,(sVector&)size.x,0,0); if(dmode&4) mesh->Face2Vert(); mesh->Sel2Mask(dmask,dmode&3); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectFace(GenMesh *mesh,sU32 dmask,sInt dmode,sInt face) { if(CheckMesh(mesh)) return 0; mesh->All2Sel(0,MAS_FACE); if(faceFace.Count && mesh->Face[face].Material) mesh->Face[face].Select = 1; mesh->Sel2Mask(dmask<<8,dmode); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SelectAngle(GenMesh *mesh,sU32 dmask,sInt dmode,sF322 dir,sF32 thresh) { sInt i; sMatrix mat; sVector dirv; if(CheckMesh(mesh)) return 0; mesh->CalcNormals(0,7); thresh = (thresh - 0.5f) * 2.0f; mat.InitEuler(dir.x*sPI2F,0.0f,dir.y*sPI2F); dirv.Init(mat.i.y,mat.j.y,mat.k.y,0.0f); for(i=0;iVert.Count;i++) mesh->Vert[i].Select = mesh->VertNorm(i).Dot3(dirv) >= thresh; mesh->Vert2FaceEdge(); if(dmode&4) mesh->Face2Vert(); mesh->Sel2Mask(dmask,dmode&3); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Bend2(GenMesh *mesh,sF323 center,sF323 rotate,sF32 len,sF32 angle) { sMatrix mt,mb; sVector vt,*vp; sF32 vx,vy,t,sa,ca; sInt i; if(CheckMesh(mesh)) return 0; mt.InitEulerPI2(&rotate.x); mt.l.x = -center.x; mt.l.y = -center.y; mt.l.z = -center.z; mb = mt; mb.TransR(); angle *= sPI2F; for(i=0;iVert.Count;i++) { vp = mesh->VertBuf + i * mesh->VertSize(); vt.Rotate34(mt,vp[0]); t = vt.y; if(t>=0.0f) vt.y -= sMin(t,len); t = sRange(t/len,1.0f,0.0f) * angle; sa = sFSin(t); ca = sFCos(t); vx = vt.x; vy = vt.y; vt.x = ca * vx - sa * vy; vt.y = sa * vx + ca * vy; vp[0].Rotate34(mb,vt); } mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SmoothAngle(GenMesh *mesh,sF32 angle) { sInt i; sVector n1,n2; if(CheckMesh(mesh)) return 0; angle = sFCos(angle * sPI2F * 0.25f); for(i=0;iEdge.Count;i++) { mesh->CalcFaceNormalAccurate(n1,mesh->GetFaceId(i*2+0)); mesh->CalcFaceNormalAccurate(n2,mesh->GetFaceId(i*2+1)); mesh->Edge[i].Select = sFAbs(n1.Dot3(n2)) < angle; } mesh->Crease(1,0,0,sGMF_NORMAL|sGMF_TANGENT); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Color(GenMesh *mesh,sF323 pos,sF322 dir,sU32 color,sF32 amplify,sF32 range,sInt op) { sInt i,j,sc,sn; sMatrix mat; sVector *vt,*vl,lightDir,d,lightCol; sF32 intens,len,rsq,invr; if(CheckMesh(mesh)) return 0; mesh->NeedAllNormals(); mat.InitEuler(dir.x*sPI2F,0.0f,dir.y*sPI2F); lightDir.Init(mat.i.y,mat.j.y,mat.k.y,0.0f); lightCol.InitColor(color); lightCol.Scale4(amplify); rsq = range * range; invr = 1.0f / range; sc = mesh->VertMap(sGMI_COLOR0); sn = mesh->VertMap(sGMI_NORMAL); for(i=0;iVert.Count;i++) { vt = mesh->VertBuf + i * mesh->VertSize(); switch(op) { case 0: // light directional intens = lightDir.Dot3(vt[sn]); if(intens > 0.0f) vt[sc].AddScale3(lightCol,intens); break; case 1: // light point d.Sub3((const sVector&) pos,vt[0]); len = d.Dot3(d); if(len < rsq) { intens = d.Dot3(vt[sn]); if(intens > 0.0f) vt[sc].AddScale3(lightCol,intens * (sFInvSqrt(len) - invr)); } break; case 2: // render slots for(j=0;jLgts.Count;j++) { vl = mesh->VertBuf + mesh->Lgts[j] * mesh->VertSize(); rsq = vl[sn+1].y; d.z = vl[0].z-vt[0].z; len = d.z*d.z; if(len < rsq) { d.x = vl[0].x-vt[0].x; len += d.x*d.x; d.y = vl[0].y-vt[0].y; len += d.y*d.y; if(len < rsq) { intens = d.x*vt[sn].x + d.y*vt[sn].y + d.z*vt[sn].z; if(intens > 0.0f) vt[sc].AddScale3(vl[sc],intens * (sFInvSqrt(len) - vl[sn+1].z)); } } } //mesh->Lgts.Count = 0; break; case 3: // ambient light vt[sc].Add3(lightCol); break; } } return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_BendS(GenMesh *mesh,sF323 anchor,sF323 rotate,sF32 len,KSpline *spline) { sMatrix mt; static sMatrix mat[129]; sVector vt,pt,dir,v0,v1,*vp; sInt i,it; sF32 t; if(!spline || CheckMesh(mesh)) return 0; mt.InitEulerPI2(&rotate.x); mt.l.x = -anchor.x; mt.l.y = -anchor.y; mt.l.z = -anchor.z; for(i=0;i<128;i++) { spline->Eval(i/128.0f,pt); spline->Eval((i+1)/128.0f,dir); dir.Sub3(pt); pt.w = 1.0f; mat[i].InitDir(dir); mat[i].l = pt; } spline->Eval(1.0f,pt); pt.w = 1.0f; mat[128].InitDir(dir); mat[128].l = pt; for(i=0;iVert.Count;i++) { vp = mesh->VertBuf + i * mesh->VertSize(); vt.Rotate34(mt,vp[0]); t = vt.z; if(t>=0.0f) vt.z -= sMin(t,len); t = sRange(t/len,1.0f,0.0f) * 128.0f; it = t; t -= it; v0.Rotate34(mat[it+0],vt); v1.Rotate34(mat[it+1],vt); vp[0].Lin3(v0,v1,t); } mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_LightSlot(sF323 pos,sU32 color,sF32 amplify,sF32 range) { GenMesh *mesh; mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1); mesh->AddNewVert(); *mesh->Lgts.Add() = 0; mesh->VertBuf[mesh->VertMap(sGMI_POS)].Init(pos.x,pos.y,pos.z,1); mesh->VertBuf[mesh->VertMap(sGMI_COLOR0)].InitColor(color); mesh->VertBuf[mesh->VertMap(sGMI_COLOR0)].Scale4(amplify); mesh->VertBuf[mesh->VertMap(sGMI_TANGENT)].Init(range,range*range,1.0f/range,0); return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_ShadowEnable(GenMesh *mesh,sBool enable) { sInt i; if(CheckMesh(mesh)) return 0; for(i=0;iFace.Count;i++) mesh->Face[i].Used = enable; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_Multiply2(sInt seed,sInt3 count1,sF323 translate1,sInt3 count2,sF323 translate2,sInt random,sInt3 count3,sF323 translate3,sInt inCount,GenMesh *inMesh,...) { if(!inCount) return 0; GenMesh *mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); sSetRndSeed(seed); sInt lastStart,start = 0; sMatrix xform; xform.Init(); if(count3.x*count3.y*count3.z * count2.x*count2.y*count2.z * count1.x*count1.y*count1.z > 1024) { count3.Init(1,1,1); count2.Init(1,1,1); count1.Init(1,1,1); } for(sInt z3=0;z3Vert.Count; GenMesh *in = (&inMesh)[sMin(sGetRnd(inCount+random),inCount-1)]; mesh->Add(in,!!start); for(sInt i=lastStart;iVert[i].Select = 0; for(sInt i=start;iVert.Count;i++) mesh->Vert[i].Select = 1; xform.l.x = x1 * translate1.x + x2 * translate2.x + x3 * translate3.x; xform.l.y = y1 * translate1.y + y2 * translate2.y + y3 * translate3.y; xform.l.z = z1 * translate1.z + z2 * translate2.z + z3 * translate3.z; mesh->TransVert(xform); } } } } } } } } } for(sInt i=0;iRelease(); mesh->GotNormals = sFALSE; return mesh; } /****************************************************************************/ GenSimpleMesh * __stdcall Mesh_BSP(GenMesh *mesh) { GenSimpleBrush ba,bb; sAABox box; if(!mesh) return 0; box.Min.Init(-1.0f,-1.0f,-1.0f,1.0f); box.Max.Init( 1.0f, 1.0f, 1.0f,1.0f); ba.Cube(box); box.Min.Init( 1.0f,-1.0f,-1.0f,1.0f); box.Max.Init( 3.0f, 1.0f, 1.0f,1.0f); bb.Cube(box); ba.CSGAgainst(bb,sTRUE); bb.CSGAgainst(ba,sTRUE); GenSimpleMesh *result = new GenSimpleMesh; result->Add(ba.Mesh); result->Add(bb.Mesh); return result; } /****************************************************************************/ GenMesh * __stdcall Mesh_XSI(sChar *filename) { GenMesh *mesh; #if sLINK_XSI sXSILoader loader; if(loader.LoadXSI(filename)) { loader.Optimise(); mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,1024); mesh->ImportXSI(&loader); } else #endif mesh = 0; return mesh; } /****************************************************************************/ GenMesh * __stdcall Mesh_SingleVert() { GenMesh *mesh = new GenMesh; mesh->Init(sGMF_DEFAULT,3); mesh->Ring(3,0,0,0); mesh->Face[1].Material = 0; mesh->Vert[0].Next = 1; mesh->Vert[1].First = 0; mesh->Vert[1].Next = 2; mesh->Vert[2].First = 0; mesh->Vert[2].Next = 0; return mesh; } /****************************************************************************/ static void ToMinVector(GenMinVector &dst,const sVector &src) { dst.x = src.x; dst.y = src.y; dst.z = src.z; } static void ToUV(sF32 *dst,const sVector &src) { dst[0] = src.x; dst[1] = src.y; } #if sLINK_MINMESH GenMinMesh * __stdcall Mesh_ToMin(GenMesh *mesh) { if(CheckMesh(mesh)) return 0; // triangulate anything with >=8 vertices mesh->Triangulate(KMM_MAXVERT); GenMinMesh *minMesh = new GenMinMesh; mesh->All2Sel(1,MAS_FACE); mesh->Face2Vert(); // count output vertices sInt outVerts = 0; for(int i=0;iVert.Count;i++) outVerts += mesh->Vert[i].Select; minMesh->Vertices.Resize(outVerts); // remap vertices outVerts = 0; sInt vs = mesh->VertSize(); sInt vc0 = mesh->VertMap(sGMI_COLOR0); sInt vu0 = mesh->VertMap(sGMI_UV0); sInt vu1 = mesh->VertMap(sGMI_UV1); sVector *vb = mesh->VertBuf; for(sInt i=0;iVert.Count;i++) { GenMeshVert *vert = &mesh->Vert[i]; if(!vert->Select) { vert->Temp = -1; continue; } GenMinVert *outVert = &minMesh->Vertices[outVerts]; vert->Temp = outVerts; outVert->Select = 0; outVert->BoneCount = 0; outVert->Color = (vc0 == -1) ? 0xffffffff : vb[i * vs + vc0].GetColor(); ToMinVector(outVert->Pos,vb[vert->First * vs]); if(vu0 != -1) ToUV(outVert->UV[0],vb[i * vs + vu0]); if(vu1 != -1) ToUV(outVert->UV[1],vb[i * vs + vu1]); outVerts++; } // convert materials to clusters for(sInt i=0;iClusters.Count;i++) { GenMinCluster *cluster = &minMesh->Clusters[i]; if(cluster->Mtrl) { cluster->Mtrl->Release(); cluster->Mtrl = 0; } } minMesh->Clusters.Resize(mesh->Mtrl.Count); for(sInt i=0;iMtrl.Count;i++) { GenMeshMtrl *inMtrl = &mesh->Mtrl[i]; GenMinCluster *outCluster = &minMesh->Clusters[i]; outCluster->Mtrl = inMtrl->Material; outCluster->RenderPass = inMtrl->Pass; outCluster->Id = i; outCluster->AnimType = 0; outCluster->AnimMatrix = -1; if(outCluster->Mtrl) outCluster->Mtrl->AddRef(); } // count faces not deleted sInt outFaceCount = 0; for(sInt i=0;iFace.Count;i++) outFaceCount += mesh->Face[i].Material != 0; // convert faces minMesh->Faces.Resize(outFaceCount); GenMinFace *outFace = &minMesh->Faces[0]; for(sInt i=0;iFace.Count;i++) { GenMeshFace *inFace = &mesh->Face[i]; if(!inFace->Material) continue; outFace->Select = 0; outFace->Count = 0; outFace->Cluster = inFace->Material; outFace->Flags = !inFace->Used; sInt e,ee; e = ee = inFace->Edge; do { sVERIFY(mesh->GetVert(e)->Temp!=-1); outFace->Vertices[outFace->Count] = mesh->GetVert(e)->Temp; outFace->Count++; e = mesh->NextFaceEdge(e); } while(e != ee && outFace->Count < 8); outFace++; } // update+cleanup minMesh->ChangeTopo(); mesh->Release(); return minMesh; } #endif /****************************************************************************/ /****************************************************************************/ #if sLINK_XSI void GenMesh::ImportXSI(sXSILoader *xsi) { sInt i,j,k,fi; sInt first; sXSIModel *xm; sXSICluster *xc; sXSIFCurve *xf; sVERIFY(KeyCount==0); sVERIFY(CurveCount==0); sVERIFY(KeyBuf==0); KeyCount = 0; CurveCount = 0; ImportXSIR(xsi->RootModel,-1); KeyBuf = new sF32[KeyCount*CurveCount]; sSetMem4((sU32 *)KeyBuf,0,KeyCount*CurveCount); for(i=0;iModels->GetCount();i++) { xm = xsi->Models->Get(i); first = Vert.Count; for(j=0;jClusters->GetCount();j++) { xc = xm->Clusters->Get(j); ImportXSI(xc,first); } Verify(); for(j=0;jFCurves->GetCount();j++) { xf = xm->FCurves->Get(j); fi = xf->Index; sVERIFY(fi>=0 && fiOffset; BoneCurve[fi].Matrix = xm->Index; for(k=0;kKeyCount;k++) { sVERIFY(xf->Keys[k].Num>=0 && xf->Keys[k].NumKeys[k].Num] = xf->Keys[k].Pos; } } } } void GenMesh::ImportXSIR(sXSIModel *xm,sInt parent) { sInt i,cm,cc,fcc; GenMeshMatrix *mat; sXSIFCurve *xfc; cm = BoneMatrix.Count; xm->Index = cm; BoneMatrix.AtLeast(cm+1); BoneMatrix.Count = cm+1; mat = &BoneMatrix[cm]; mat->BaseSRT[0] = xm->BaseS.x; mat->BaseSRT[1] = xm->BaseS.y; mat->BaseSRT[2] = xm->BaseS.z; mat->BaseSRT[3] = xm->BaseR.x; mat->BaseSRT[4] = xm->BaseR.y; mat->BaseSRT[5] = xm->BaseR.z; mat->BaseSRT[6] = xm->BaseT.x; mat->BaseSRT[7] = xm->BaseT.y; mat->BaseSRT[8] = -xm->BaseT.z; mat->TransSRT[0] = xm->TransS.x; mat->TransSRT[1] = xm->TransS.y; mat->TransSRT[2] = xm->TransS.z; mat->TransSRT[3] = xm->TransR.x; mat->TransSRT[4] = xm->TransR.y; mat->TransSRT[5] = xm->TransR.z; mat->TransSRT[6] = xm->TransT.x; mat->TransSRT[7] = xm->TransT.y; mat->TransSRT[8] = -xm->TransT.z; mat->Matrix.Init(); mat->Parent = parent; mat->Used = 0; fcc = xm->FCurves->GetCount(); if(fcc>0) { cc = BoneCurve.Count; BoneCurve.AtLeast(cc+fcc); BoneCurve.Count = cc+fcc; for(i=0;iFCurves->Get(i); KeyCount = sMax(KeyCount,xfc->Keys[xfc->KeyCount-1].Num+1); xfc->Index = cc+i; } CurveCount+=fcc; } for(i=0;iChilds->GetCount();i++) ImportXSIR(xm->Childs->Get(i),cm); } static sInt VectorHash(const sVector &v) { sU32 *bits = (sU32 *) &v.x; // FNV-based hash on x,y,z sU32 hash = 0x9dc5; hash = (hash ^ bits[0]) * 0x0193; hash = (hash ^ bits[1]) * 0x0193; hash = (hash ^ bits[2]) * 0x0193; return hash & 0x3ff; } void GenMesh::ImportXSI(sXSICluster *xc,sInt first) { sInt i,j,vc,fc,max; sVector v; sVector *vp; sInt vi,vj,fi; sInt *fp; sInt edges[64]; sInt hashbucket[1024],vhash; sDPrintF("cluster %08x\n",xc); vc = Vert.Count; Vert.AtLeast(vc+xc->VertexCount); Realloc(vc+xc->VertexCount); // clear hash buckets for(i=0;i<1024;i++) hashbucket[i] = -1; // add vertices for(i=0;iVertexCount;i++) { v = xc->Vertices[i].Pos; vhash = VectorHash(v); for(j=hashbucket[vhash];j!=-1;j=Vert[j].Temp) { vp = &VertPos(j); if(v.x == vp->x && v.y == vp->y && -v.z == vp->z) { vi = j; goto vertfound; } } vi = Vert.Count; vertfound: vj = Vert.Count++; xc->Vertices[i].Temp = vj; vp = &VertPos(vj); *vp = xc->Vertices[i].Pos; vp->z = -vp->z; vp->w = 1; vp++; Vert[vj].Init(); Vert[vj].Temp2 = -1; // used for addedge if(vi == vj) // vertex was new, add to hash table { Vert[vi].Temp = hashbucket[vhash]; hashbucket[vhash] = vi; } for(j=0;j<4;j++) { if(jVertices[i].WeightCount) { Vert[vj].Matrix[j] = xc->Vertices[i].WeightModel[j]->Index; Vert[vj].Weight[j] = xc->Vertices[i].Weight[j]*255/100; } else { Vert[vj].Matrix[j] = 0xff; Vert[vj].Weight[j] = 0x00; } } if(VertMask() & sGMF_NORMAL) { *vp = xc->Vertices[i].Normal; vp->w = 0; vp++; } if(VertMask() & sGMF_TANGENT) { vp->Init4(0,0,0,0); vp++; } if(VertMask() & sGMF_COLOR0) { vp->Init4(((xc->Vertices[i].Color>>16)&0xff)/255.0f, ((xc->Vertices[i].Color>> 8)&0xff)/255.0f, ((xc->Vertices[i].Color )&0xff)/255.0f, ((xc->Vertices[i].Color>>24)&0xff)/255.0f); vp++; } if(VertMask() & sGMF_COLOR1) { vp->Init4(1,1,1,1); vp++; } if(VertMask() & sGMF_UV0) { vp->Init(xc->Vertices[i].UV[0][0],xc->Vertices[i].UV[0][1],0,0); //vp->Init(xc->Vertices[i].Pos.x*0.1,xc->Vertices[i].Pos.y*0.1,0,0); vp++; } if(VertMask() & sGMF_UV1) { vp->Init(xc->Vertices[i].UV[1][0],xc->Vertices[i].UV[1][1],0,0); vp++; } if(VertMask() & sGMF_UV2) { vp->Init(xc->Vertices[i].UV[2][0],xc->Vertices[i].UV[2][1],0,0); vp++; } if(VertMask() & sGMF_UV3) { vp->Init(xc->Vertices[i].UV[3][0],xc->Vertices[i].UV[3][1],0,0); vp++; } sVERIFY(vp==&VertBuf[(vj+1)*VertSize()]); if(vi==vj) { Vert[vj].Next = vi; Vert[vi].First = vj; } else { sVERIFY(Vert[vi].First == vi); Vert[vj].Next = Vert[vi].Next; Vert[vj].First = vi; Vert[vi].Next = vj; } } // add faces fp = xc->Faces; fc = 0; while(fpFaces+xc->IndexCount*2) { max = *fp; sVERIFY(max>0); sVERIFY(max<64); fi = Face.Count; Face.AtLeast(fi+1); Face.Count=fi+1; Face[fi].Init(); Face[fi].Material = 1; vi = fp[1];//max*2-1]; for(i=0;iVertices[vj].Temp,xc->Vertices[vi].Temp,fi); } fp += max*2; for(i=0;i