Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
fr_public/genthree/genmesh.cpp
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
5442 lines (4561 sloc)
103 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This file is distributed under a BSD license. See LICENSE.txt for details. | |
| #include "cslrt.hpp" | |
| #include "genmesh.hpp" | |
| #include "genmaterial.hpp" | |
| #include "genbitmap.hpp" | |
| #include "_util.hpp" | |
| /****************************************************************************/ | |
| #define RBCOUNTMAX (1024*1024*2) | |
| static sU32 RBData[RBCOUNTMAX]; | |
| static sMatrix RBMat[1024]; | |
| static sObject *RBObj[256]; | |
| static sInt RBCount; | |
| static sInt RBIndex; | |
| static sInt RBObjIndex; | |
| static GenMesh *RBMesh; | |
| sMAKEZONE(MeshPlay ,"MeshPlay" ,0xff000080); | |
| sMAKEZONE(MeshPaint,"MeshPaint",0xff0000ff); | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void GenMeshElem::InitElem() | |
| { | |
| Mask = 0; | |
| Id = 0; | |
| Select = 0; | |
| Used = 1; | |
| } | |
| void GenMeshElem::SelElem(sU32 mask1,sU32 mask0) | |
| { | |
| Mask = (Mask & ~mask0) | mask1; | |
| } | |
| 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; | |
| } | |
| void GenMeshPass::Init() | |
| { | |
| MatPass = 0; | |
| Reset(); | |
| } | |
| void GenMeshPass::Reset() | |
| { | |
| sInt i; | |
| for(i=0;i<GENMAT_MAXBATCH;i++) | |
| { | |
| Geometry[i] = 0; | |
| IndexCount[i] = 0; | |
| VertexCount[i] = 0; | |
| } | |
| MatPass = 0; | |
| BatchCount = 0; | |
| } | |
| void GenMeshMtrl::Init() | |
| { | |
| sInt i; | |
| InitElem(); | |
| for(i=0;i<GENMAT_MAXPASS;i++) | |
| Pass[i].Init(); | |
| Material = 0; | |
| } | |
| void GenMeshAnim::Copy(sObject *o) | |
| { | |
| GenMeshAnim *oa; | |
| sVERIFY(o->GetClass()==sCID_GENMESHANIM); | |
| oa = (GenMeshAnim *)o; | |
| s = oa->s; | |
| r = oa->r; | |
| t = oa->t; | |
| v = oa->v; | |
| p = oa->p; | |
| MatrixIndex = oa->MatrixIndex; | |
| Operation = oa->Operation; | |
| Flags = oa->Flags; | |
| _Label = oa->_Label; | |
| OMat = oa->OMat; | |
| OVec = oa->OVec; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| GenMesh::GenMesh() | |
| { | |
| Vert.Init(16); | |
| Edge.Init(16); | |
| Face.Init(16); | |
| Mtrl.Init(16); | |
| Mtrl.Count = 2; | |
| Mtrl[0].Init(); | |
| Mtrl[1].Init(); | |
| VertMask = 0; | |
| VertSize = 0; | |
| VertAlloc = 0; | |
| VertCount = 0; | |
| VertBuf = 0; | |
| BoneMatrix.Init(); | |
| BoneCurve.Init(); | |
| KeyCount = 0; | |
| CurveCount = 0; | |
| KeyBuf = 0; | |
| Prepared = 0; | |
| Anim0 = 0; | |
| Anim1 = 16; | |
| StoreMode = 0; | |
| RecMode = 0; | |
| RecLevel = 0; | |
| RecVert.Init(); | |
| RecMat.Init(); | |
| RecObj.Init(); | |
| RecCmd.Init(); | |
| RecOpCount = 0; | |
| RecOpCountPtr = 0; | |
| RecCommandLevel = -1; | |
| sSetMem(AnimLabels,0,sizeof(AnimLabels)); | |
| AnimLabelCount = 0; | |
| AnimLabelLastMat = 0; | |
| AnimLabelLastOp = GMA_NOP; | |
| } | |
| GenMesh::~GenMesh() | |
| { | |
| sInt i,j,k; | |
| for(i=0;i<Mtrl.Count;i++) | |
| { | |
| for(j=0;j<GENMAT_MAXPASS;j++) | |
| { | |
| for(k=0;k<Mtrl[i].Pass[j].BatchCount;k++) | |
| { | |
| if(Mtrl[i].Pass[j].Geometry[k]) | |
| sSystem->GeoRem(Mtrl[i].Pass[j].Geometry[k]); | |
| if(Mtrl[i].Pass[j].IndexBuffers[k]) | |
| delete[] Mtrl[i].Pass[j].IndexBuffers[k]; | |
| if(Mtrl[i].Pass[j].VertexBuffers[k]) | |
| delete[] Mtrl[i].Pass[j].VertexBuffers[k]; | |
| } | |
| } | |
| } | |
| Vert.Exit(); | |
| Edge.Exit(); | |
| Face.Exit(); | |
| Mtrl.Exit(); | |
| BoneMatrix.Exit(); | |
| BoneCurve.Exit(); | |
| RecVert.Exit(); | |
| RecMat.Exit(); | |
| RecObj.Exit(); | |
| RecCmd.Exit(); | |
| if(VertBuf) | |
| delete[] VertBuf; | |
| if(KeyBuf) | |
| delete[] KeyBuf; | |
| } | |
| void GenMesh::Tag() | |
| { | |
| sInt i,j; | |
| GenMeshMtrl *gmm; | |
| for(i=0;i<Mtrl.Count;i++) | |
| { | |
| gmm = &Mtrl[i]; | |
| sBroker->Need(gmm->Material); | |
| for(j=0;j<GENMAT_MAXPASS;j++) | |
| sBroker->Need(gmm->Pass[j].MatPass); | |
| } | |
| for(i=0;i<RecObj.Count;i++) | |
| sBroker->Need(RecObj.Array[i]); | |
| for(i=0;i<AnimLabelCount;i++) | |
| sBroker->Need(AnimLabels[i]); | |
| } | |
| void GenMesh::Copy(sObject *o) | |
| { | |
| GenMesh *om; | |
| sInt i,j; | |
| sVERIFY(o->GetClass()==sCID_GENMESH); | |
| om = (GenMesh *)o; | |
| sVERIFY(om->RecMode==0); | |
| _Label = om->_Label; | |
| Vert.Copy(om->Vert); | |
| Edge.Copy(om->Edge); | |
| Face.Copy(om->Face); | |
| Mtrl.Copy(om->Mtrl); | |
| for(i=0;i<Mtrl.Count;i++) | |
| { | |
| for(j=0;j<GENMAT_MAXPASS;j++) | |
| Mtrl[i].Pass[j].Reset(); | |
| } | |
| Prepared = 0; | |
| Anim0 = om->Anim0; | |
| Anim1 = om->Anim1; | |
| Init(om->VertMask,om->VertAlloc); | |
| sVERIFY(VertSize==om->VertSize); | |
| sCopyMem4((sU32 *)VertBuf,(sU32 *)om->VertBuf,om->VertSize*om->VertCount*4); | |
| VertCount = om->VertCount; | |
| 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); | |
| } | |
| StoreMode = om->StoreMode; | |
| RecVert.Copy(om->RecVert); | |
| RecCmd.Copy(om->RecCmd); | |
| RecMat.Copy(om->RecMat); | |
| RecObj.Copy(om->RecObj); | |
| AnimLabelCount = om->AnimLabelCount; | |
| AnimLabelLastMat = om->AnimLabelLastMat; | |
| AnimLabelLastOp = om->AnimLabelLastOp; | |
| for(i=0;i<om->AnimLabelCount;i++) | |
| { | |
| AnimLabels[i] = new GenMeshAnim; | |
| AnimLabels[i]->Copy(om->AnimLabels[i]); | |
| } | |
| } | |
| 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<<colorSets)-1)<<sGMI_COLOR0) | |
| |(((1<<uvSets)-1)<<sGMI_UV0); | |
| } | |
| void GenMesh::Init(sU32 vertmask,sInt vertcount) | |
| { | |
| sInt i; | |
| sREGZONE(MeshPlay); | |
| sREGZONE(MeshPaint); | |
| VertMask = vertmask; | |
| #if sINTRO | |
| sVERIFY(vertmask == 0x23); | |
| #endif | |
| VertSize = 0; | |
| VertAlloc = vertcount; | |
| VertCount = 0; | |
| for(i=0;i<16;i++) | |
| { | |
| if(VertMask & (1<<i)) | |
| VertMap[i] = VertSize++; | |
| else | |
| VertMap[i] = -1; | |
| } | |
| sVERIFY(VertSize); | |
| sVERIFY(VertMask&1); | |
| VertBuf = new sVector[VertSize*VertAlloc]; | |
| sSetMem4((sU32*)VertBuf,0,VertSize*VertAlloc*4); | |
| Vert.AtLeast(vertcount); | |
| Edge.AtLeast(vertcount*2); | |
| Face.AtLeast(vertcount/2); | |
| } | |
| void GenMesh::Realloc(sInt vertcount) | |
| { | |
| sInt ns; | |
| sVector *nd; | |
| if(vertcount>=VertAlloc) | |
| { | |
| #if !sINTRO | |
| sDPrintF("realloc %d\n",vertcount); | |
| #endif | |
| ns = sMax(vertcount,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; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| sU32 *GenMesh::RecBegin(sU32 command) | |
| { | |
| if(RecMode==0) | |
| { | |
| sVERIFY(RBMesh==0); | |
| sVERIFY(RecLevel==0); | |
| RBCount = 0; | |
| RBIndex = RecMat.Count; | |
| RBObjIndex = RecObj.Count; | |
| RBMesh = this; | |
| RecMode=1; | |
| } | |
| RecLevel++; | |
| if (command) | |
| { | |
| sVERIFY(RecCommandLevel == -1); | |
| RBData[RBCount++] = command; | |
| RecOpCountPtr = RBData + RBCount++; | |
| RecLastSource = 0; | |
| RecLastDest = 0; | |
| RecOpCount = 0; | |
| RecCommandLevel = RecLevel - 1; | |
| } | |
| return RBData+RBCount; | |
| } | |
| void GenMesh::RecEnd(sU32 *data) | |
| { | |
| RBCount = data-RBData; | |
| RecEnd(); | |
| } | |
| void GenMesh::RecEnd() | |
| { | |
| sInt o,n; | |
| RecLevel--; | |
| if(RecLevel==RecCommandLevel) | |
| { | |
| *RecOpCountPtr = RecOpCount; | |
| RecCommandLevel = -1; | |
| } | |
| if(RecLevel==0 && StoreMode) | |
| { | |
| o = RecCmd.Count; | |
| n = o+RBCount; | |
| if(n!=o) | |
| { | |
| RecCmd.SetMax(n+1); | |
| RecCmd.Count = n; | |
| sCopyMem(RecCmd.Array+o,RBData,sizeof(sU32)*(n-o)); | |
| RecCmd.Array[n] = 0; | |
| } | |
| o = RecMat.Count; | |
| n = RBIndex; | |
| if(n!=o) | |
| { | |
| RecMat.SetMax(n); | |
| RecMat.Count = n; | |
| sCopyMem(RecMat.Array+o,RBMat+o,sizeof(sMatrix)*(n-o)); | |
| } | |
| o = RecObj.Count; | |
| n = RBObjIndex; | |
| if(n!=o) | |
| { | |
| RecObj.SetMax(n); | |
| RecObj.Count = n; | |
| sCopyMem(RecObj.Array+o,RBObj+o,sizeof(sObject*)*(n-o)); | |
| } | |
| } | |
| if(RecLevel==0) | |
| { | |
| RBData[RBCount++] = 0; | |
| sVERIFY(RecMode!=0); | |
| sVERIFY(RBMesh==this); | |
| sVERIFY(RBCount<RBCOUNTMAX); | |
| sVERIFY(RBIndex<1024); | |
| sVERIFY(RBObjIndex<256); | |
| if(RecMode==1) | |
| RecPlay(RBData,RBMat,RBObj); | |
| RBMesh = 0; | |
| RBCount = 0; | |
| RBIndex = 0; | |
| RBObjIndex = 0; | |
| RecMode = 0; | |
| } | |
| } | |
| void GenMesh::RecStoreMode() | |
| { | |
| sInt n; | |
| if(!StoreMode) | |
| { | |
| StoreMode = 1; | |
| n = VertCount*VertSize; | |
| RecVert.SetMax(n); | |
| RecVert.Count = n; | |
| sCopyMem(RecVert.Array,VertBuf,sizeof(sVector)*n); | |
| } | |
| } | |
| void GenMesh::RecReplay() | |
| { | |
| sInt i,j; | |
| GenMeshAnim *gma; | |
| sMatrix mat; | |
| sF32 srt[12]; | |
| #if !sINTRO | |
| srt[0] = 1; srt[1] = 1; srt[2] = 1; | |
| srt[3] = 0; srt[4] = 0; srt[5] = 0; | |
| srt[6] = 0; srt[7] = 0; srt[8] = 0; | |
| srt[9] = 0; srt[10]= 0; srt[11]= 0; | |
| #endif | |
| if(StoreMode && RecCmd.Count>0) | |
| { | |
| for(i=0;i<AnimLabelCount;i++) | |
| { | |
| gma = AnimLabels[i]; | |
| if(!(gma->Flags & GMF_DOUBLE)) | |
| for(j=0;j<12;j++) | |
| srt[j] = (&gma->s.x)[j]/65536.0f; | |
| switch(gma->Operation) | |
| { | |
| case GMA_TRANSFORM: | |
| mat.InitSRT(srt); | |
| RecMat.Array[gma->MatrixIndex].Mul4(gma->OMat,mat); | |
| break; | |
| case GMA_PERLIN: | |
| mat.InitSRT(srt); | |
| RecMat.Array[gma->MatrixIndex].Mul4(gma->OMat,mat); | |
| RecMat.Array[gma->MatrixIndex+1].i.Init(srt[9],srt[10],srt[11]); | |
| RecMat.Array[gma->MatrixIndex+1].i.Add3(gma->OVec); | |
| break; | |
| case GMA_BONE: | |
| BonesModify(gma->MatrixIndex,((gma->p + sFtol(gma->OMat.i.x*65536.0f))&0xffff)/65536.0f); | |
| break; | |
| case GMA_EWK: | |
| RecMat.Array[gma->MatrixIndex] = gma->OMat; | |
| RecMat.Array[gma->MatrixIndex].i.x *= srt[0]; | |
| RecMat.Array[gma->MatrixIndex].i.y *= srt[1]; | |
| RecMat.Array[gma->MatrixIndex].i.z *= srt[2]; | |
| RecMat.Array[gma->MatrixIndex].i.w += gma->p/65536.0f; | |
| RecMat.Array[gma->MatrixIndex].j.x += srt[3]; | |
| RecMat.Array[gma->MatrixIndex].j.y += srt[4]; | |
| RecMat.Array[gma->MatrixIndex].j.z += srt[5]; | |
| break; | |
| } | |
| } | |
| sCopyMem(VertBuf,RecVert.Array,sizeof(sVector)*RecVert.Count); | |
| RecPlay(RecCmd.Array,RecMat.Array,RecObj.Array); | |
| } | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::MarkAnimLabel(sInt mode) | |
| { | |
| if(StoreMode) | |
| { | |
| AnimLabelLastOp = mode; | |
| AnimLabelLastMat = RecMat.Count; | |
| } | |
| } | |
| void GenMesh::SetAnimLabel(sInt label,sU32 flags) | |
| { | |
| GenMeshAnim *gma; | |
| if(StoreMode && AnimLabelCount<32 && AnimLabelLastOp!=GMA_NOP) | |
| { | |
| gma = new GenMeshAnim; | |
| gma->Flags = flags; | |
| gma->s.Init(0x10000,0x10000,0x10000); | |
| sSetMem4((sU32 *)&gma->r,0,3*3+1); // r,t,v,p | |
| gma->MatrixIndex = AnimLabelLastMat; | |
| gma->Operation = AnimLabelLastOp; | |
| gma->OMat = RecMat[AnimLabelLastMat]; | |
| if(AnimLabelLastMat+1<RecMat.Count) | |
| gma->OVec = RecMat[AnimLabelLastMat+1].i; | |
| gma->_Label = label; | |
| if(flags & GMF_DOUBLE) | |
| gma->_Label = 0; | |
| AnimLabels[AnimLabelCount++] = gma; | |
| } | |
| } | |
| /****************************************************************************/ | |
| sInt GenMesh::RecMatrix(const sMatrix &mat) | |
| { | |
| RBMat[RBIndex] = mat; | |
| return RBIndex++; | |
| } | |
| sInt GenMesh::RecObject(sObject *obj) | |
| { | |
| RBObj[RBObjIndex] = obj; | |
| return RBObjIndex++; | |
| } | |
| void GenMesh::RecPlay(sU32 *data,sMatrix *matrices,sObject **objects) | |
| { | |
| sZONE(MeshPlay); | |
| while (*data) | |
| { | |
| switch (*data++) | |
| { | |
| case IM_XFORM: data = RecTransformInner(data,matrices); break; | |
| case IM_BONE: data = RecBoneInner(data,matrices); break; | |
| case IM_ADDSCL: data = RecAddScaleInner(data,matrices); break; | |
| case IM_NORMAL: data = RecNormalInner(data,matrices); break; | |
| #if !sINTRO_X | |
| case IM_DISPLACE: data = RecDisplaceInner(data,matrices,objects); break; | |
| case IM_BEVEL: data = RecBevelInner(data,matrices); break; | |
| #endif | |
| case IM_PERLIN: data = RecPerlinInner(data,matrices); break; | |
| case IM_COPY: data = RecCopyInner(data,matrices,objects); break; | |
| case IM_F2VN: data = RecF2VNInner(data,matrices); break; | |
| case IM_EWK: data = RecEWKInner(data,matrices); break; | |
| } | |
| } | |
| } | |
| sU32 *GenMesh::RecSourceInd(sU32 *data,sInt ind) | |
| { | |
| *data++ = (ind - RecLastSource) * sizeof(sVector); | |
| RecLastSource = ind; | |
| return data; | |
| } | |
| sU32 *GenMesh::RecDestInd(sU32 *data,sInt ind) | |
| { | |
| *data++ = (ind - RecLastDest) * sizeof(sVector); | |
| RecLastDest = ind; | |
| return data; | |
| } | |
| void GenMesh::RecAddScaleArray(sInt dest,sU32 count,sInt mode,sU32* dptr) | |
| { | |
| sU32 *data; | |
| sInt i,j,o,v,flg; | |
| dest *= VertSize; | |
| data = RecBegin(); | |
| mode &= VertMask; | |
| for(j=0;j<=sGMI_LAST;j++) | |
| { | |
| flg = 1 << j; | |
| if (mode & flg) | |
| { | |
| o = VertMap[j]; | |
| sVERIFY(o != -1); | |
| RecOpCount++; | |
| *data++ = count; | |
| for(i=0;i<(sInt)count;i++) | |
| { | |
| v = dptr[i*2]*VertSize+o; | |
| *data++ = (v - RecLastSource) * sizeof(sVector); | |
| RecLastSource = v; | |
| *data++ = dptr[i*2+1]; | |
| } | |
| *data++ = (dest + o - RecLastDest) * sizeof(sVector); | |
| RecLastDest = dest + o; | |
| } | |
| } | |
| RecEnd(data); | |
| } | |
| void GenMesh::RecAddScale(sInt dest,sU32 count,sInt mode,...) | |
| { | |
| sU32 values[64*2]; | |
| sU32 i; | |
| sF32 ftemp; | |
| sVERIFY(count < 64); | |
| for(i=0;i<count;i++) | |
| { | |
| values[i*2+0] = sVARARG(&mode,i*3); | |
| ftemp = sVARARGF(&mode,i*3+1); | |
| values[i*2+1] = *((sU32*) &ftemp); | |
| } | |
| RecAddScaleArray(dest,count,mode,values); | |
| } | |
| sU32 *GenMesh::RecTransformInner(sU32 *data,sMatrix *matrices) | |
| { | |
| sVector *src,*dst; | |
| sU32 count,sj,dj,vert; | |
| sF32 sx,sy,sz,f; | |
| sMatrix *mtx; | |
| count = *data++; | |
| sj = *data++; | |
| dj = *data++; | |
| mtx = matrices + *data++; | |
| if(dj&0x10) | |
| { | |
| dj &= 0x0f; | |
| f = 1.0f; | |
| } | |
| else | |
| f = 0.0f; | |
| while (count--) | |
| { | |
| vert = *data++; | |
| src = VertBuf + vert * VertSize + sj; | |
| dst = VertBuf + vert * VertSize + dj; | |
| sx = src->x; sy = src->y; sz = src->z; | |
| dst->x = dst->x*f+sx*mtx->i.x+sy*mtx->j.x+sz*mtx->k.x+src->w*mtx->l.x; | |
| dst->y = dst->y*f+sx*mtx->i.y+sy*mtx->j.y+sz*mtx->k.y+src->w*mtx->l.y; | |
| dst->z = dst->z*f+sx*mtx->i.z+sy*mtx->j.z+sz*mtx->k.z+src->w*mtx->l.z; | |
| dst->w = src->w; | |
| } | |
| return data; | |
| } | |
| sU32 *GenMesh::RecBoneInner(sU32 *data,sMatrix *matrices) | |
| { | |
| sU32 count; | |
| sVector *vtx; | |
| sMatrix *mtx; | |
| sF32 weight,dx,dy,dz; | |
| sInt i; | |
| count = *data++; | |
| while(count--) | |
| { | |
| vtx = VertBuf + *data++; | |
| dx = dy = dz = 0.0f; | |
| for(i=0;i<4;i++) | |
| { | |
| weight = (sF32 &) *data++; | |
| mtx = matrices + *data++; | |
| dx+=weight*(vtx->x*mtx->i.x+vtx->y*mtx->j.x+vtx->z*mtx->k.x+mtx->l.x); | |
| dy+=weight*(vtx->x*mtx->i.y+vtx->y*mtx->j.y+vtx->z*mtx->k.y+mtx->l.y); | |
| dz+=weight*(vtx->x*mtx->i.z+vtx->y*mtx->j.z+vtx->z*mtx->k.z+mtx->l.z); | |
| } | |
| vtx->x = dx; | |
| vtx->y = dy; | |
| vtx->z = dz; | |
| } | |
| return data; | |
| } | |
| sU32 *GenMesh::RecAddScaleInner(sU32 *code,sMatrix *matrices) | |
| { | |
| sU32 count,vcount; | |
| sF32 *src,*dst; | |
| sF32 sx,sy,sz,sw,wgt; | |
| count = *code++; | |
| dst = src = (sF32 *)VertBuf; | |
| #if !sINTRO | |
| if(sSystem_::CpuMask&sCPU_3DNOW2) | |
| { | |
| _asm | |
| { | |
| femms; | |
| mov ebx, [code]; | |
| mov esi, [src]; | |
| mov edi, esi; | |
| mov edx, [count]; | |
| or edx, edx; | |
| jz end; | |
| vertloop: | |
| pxor mm0, mm0; | |
| pxor mm1, mm1; | |
| mov ecx, [ebx]; | |
| lea ebx, [ebx + ecx * 8 + 8]; | |
| neg ecx; | |
| jz noverts; | |
| sumloop: | |
| movd mm2, [ebx + ecx * 8]; | |
| add esi, [ebx + ecx * 8 - 4]; | |
| punpckldq mm2, mm2; | |
| movq mm3, mm2; | |
| pfmul mm2, [esi]; | |
| pfmul mm3, [esi + 8]; | |
| pfadd mm0, mm2; | |
| pfadd mm1, mm3; | |
| inc ecx; | |
| jnz sumloop; | |
| noverts: | |
| add edi, [ebx - 4]; | |
| movntq [edi], mm0; | |
| movntq [edi + 8], mm1; | |
| dec edx; | |
| jnz vertloop; | |
| end: | |
| mov [code], ebx; | |
| femms; | |
| } | |
| } | |
| else | |
| #endif | |
| { | |
| // So ein bischen reverse engeneering kann mich nicht aufhalten... :-) | |
| // dein assemblercode ist aber schick geworden, den mußte ich echt drei mal lesen. | |
| while (count--) | |
| { | |
| vcount = *code++; | |
| sx = sy = sz = sw = 0.0f; | |
| do | |
| { | |
| src = (sF32 *)(((sU8 *)src)+(*code++)); | |
| wgt = *((sF32*) code); code++; | |
| sx += wgt * src[0]; | |
| sy += wgt * src[1]; | |
| sz += wgt * src[2]; | |
| sw += wgt * src[3]; | |
| } | |
| while (--vcount); | |
| dst = (sF32 *)(((sU8 *)dst)+(*code++)); | |
| dst[0] = sx; | |
| dst[1] = sy; | |
| dst[2] = sz; | |
| dst[3] = sw; | |
| } | |
| } | |
| return code; | |
| } | |
| sU32 *GenMesh::RecNormalInner(sU32 *code,sMatrix *matrices) | |
| { | |
| sInt count,vcount; | |
| sU8 *verts; | |
| sVector *vd,*v0,*v1,*v2,nm; | |
| sVector n,t,t1,t2; | |
| sF32 t1l,t2l; | |
| sInt sn,mask,oldcw; | |
| count = *code++; | |
| verts = (sU8*) &VertBuf[0]; | |
| sn = VertMap[sGMI_NORMAL]; | |
| mask = *code++; | |
| __asm | |
| { | |
| fstcw [oldcw]; | |
| finit; | |
| push 047fh; | |
| fldcw [esp]; | |
| pop eax; | |
| } | |
| // calc the normals | |
| while(count--) | |
| { | |
| vcount = *code++; | |
| vd = (sVector *) (verts + *code++); | |
| v0 = (sVector *) (verts + *code++); | |
| v2 = (sVector *) (verts + *code++); | |
| t2.Sub3(*v2,*v0); t2l = t2.Abs3(); | |
| n.Init4(0.0f,0.0f,0.0f,0.0f); | |
| t.Init4(0.0f,0.0f,0.0f,0.0f); | |
| while(--vcount>0) | |
| { | |
| t1 = t2; t1l = t2l; v1 = v2; | |
| v0 = (sVector *) (verts + *code++); | |
| v2 = (sVector *) (verts + *code++); | |
| t2.Sub3(*v2,*v0); t2l = t2.Abs3(); | |
| if(mask&1) // normals? | |
| { | |
| nm.Cross3(t1,t2); | |
| if(t1l*t2l>1e-20f) | |
| n.AddScale3(nm,1.0f/(t1l*t2l)); | |
| } | |
| } | |
| if(mask&1) | |
| { | |
| n.UnitSafe3(); | |
| vd[sn] = n; | |
| } | |
| } | |
| __asm fldcw [oldcw]; | |
| return code; | |
| } | |
| #if !sINTRO_X | |
| sU32 *GenMesh::RecDisplaceInner(sU32 *code,sMatrix *matrices,sObject **objects) | |
| { | |
| sInt sn,su,u,v,xm,ym; | |
| sU16 *height; | |
| sU32 count; | |
| sVector *vert; | |
| GenBitmap *bmp; | |
| sF32 ampl,tu,tv,h0,h1; | |
| count = *code++; | |
| bmp = (GenBitmap *) objects[*code++]; | |
| ampl = *((sF32 *) code); code++; | |
| ampl /= 32767.0f; | |
| sn = VertMap[sGMI_NORMAL]; | |
| su = VertMap[sGMI_UV0]; | |
| height = (sU16 *) bmp->Data; | |
| xm = bmp->XSize - 1; | |
| ym = bmp->YSize - 1; | |
| while(count--) | |
| { | |
| vert = VertBuf + *code++; | |
| // get uv and sample texture | |
| tu=vert[su].x*bmp->XSize; u=tu; tu-=u; if(tu<0.0f) tu+=1.0f; u&=xm; | |
| tv=vert[su].y*bmp->YSize; v=tv; tv-=v; if(tv<0.0f) tv+=1.0f; v&=ym; | |
| h0 = height[(v*bmp->XSize+u)*4]; | |
| h0 = h0 + (height[(v*bmp->XSize+((u+1)&xm))*4] - h0) * tu; | |
| v = (v+1)&ym; | |
| h1 = height[(v*bmp->XSize+u)*4]; | |
| h1 = h1 + (height[(v*bmp->XSize+((u+1)&xm))*4] - h1) * tu; | |
| h0 = (h0 + (h1 - h0) * tv) * ampl; | |
| // perform displacement | |
| vert->x += vert[sn].x * h0; | |
| vert->y += vert[sn].y * h0; | |
| vert->z += vert[sn].z * h0; | |
| } | |
| return code; | |
| } | |
| #endif | |
| #if !sINTRO_X | |
| sU32 *GenMesh::RecBevelInner(sU32 *code,sMatrix *matrices) | |
| { | |
| sU32 count; | |
| sF32 pull; | |
| sInt pv,v,nv,vd,sn,i,sj; | |
| sVector d0,d1,t; | |
| sVector *vert,*dvert; | |
| static sInt items[5] = { sGMI_POS,sGMI_UV0,sGMI_UV1,sGMI_UV2,sGMI_UV3 }; | |
| count = *code++; | |
| pull = *((sF32 *) code); code++; | |
| sn = VertMap[sGMI_NORMAL]; | |
| while (count--) | |
| { | |
| pv = *code++; | |
| v = *code++; | |
| nv = *code++; | |
| vd = *code++; | |
| vert = &VertBuf[v*VertSize]; | |
| dvert = &VertBuf[vd*VertSize]; | |
| sCopyMem(dvert,vert,sizeof(sVector)*VertSize); | |
| for(i=0;i<5;i++) | |
| { | |
| sj=VertMap[items[i]]; | |
| if(sj!=-1) | |
| { | |
| // calculate pull-in vector | |
| d0.Sub3(VertBuf[pv*VertSize+sj],vert[sj]); d0.UnitSafe3(); | |
| d1.Sub3(VertBuf[nv*VertSize+sj],vert[sj]); d1.UnitSafe3(); | |
| t.Add3(d0,d1); | |
| if(t.Abs3()<1e-5f) | |
| t.Cross3(d1,VertNorm(v)); // fixme | |
| // do it. | |
| dvert[sj].x += pull*t.x; | |
| dvert[sj].y += pull*t.y; | |
| dvert[sj].z += pull*t.z; | |
| } | |
| } | |
| } | |
| return code; | |
| } | |
| #endif | |
| sU32 *GenMesh::RecPerlinInner(sU32 *code,sMatrix *matrices) | |
| { | |
| //#if !sINTRO_X | |
| sU32 count; | |
| sVector amp,*vert; | |
| sF32 fs[3]; | |
| sInt i,is[3],oldcw,mat; | |
| sVector t0,t1,t2; | |
| count = *code++; | |
| mat = *code++; | |
| amp = matrices[mat+1].i; | |
| // single precision, round towards neg. inf. | |
| __asm | |
| { | |
| fstcw [oldcw]; | |
| push 0143fh; | |
| fldcw [esp]; | |
| pop eax; | |
| } | |
| while(count--) | |
| { | |
| vert = &VertBuf[*code++ * VertSize]; | |
| // sampling points | |
| t0.Rotate34(matrices[mat],*vert); | |
| for(i=0;i<3;i++) | |
| { | |
| fs[i] = (&t0.x)[i]; | |
| is[i] = sFtol(fs[i]); | |
| fs[i] -= is[i]; | |
| is[i] &= 255; | |
| fs[i] = fs[i]*fs[i]*fs[i]*(10.0f+fs[i]*(6.0f*fs[i]-15.0f)); | |
| } | |
| #define ix is[0] | |
| #define iy is[1] | |
| #define iz is[2] | |
| #define P sPerlinPermute | |
| #define G sPerlinGradient3D | |
| // trilerp | |
| t0.Lin3(G[P[P[P[ix]+iy]+iz]&15],G[P[P[P[ix+1]+iy]+iz]&15],fs[0]); | |
| t1.Lin3(G[P[P[P[ix]+iy+1]+iz]&15],G[P[P[P[ix+1]+iy+1]+iz]&15],fs[0]); | |
| t0.Lin3(t0,t1,fs[1]); | |
| t1.Lin3(G[P[P[P[ix]+iy]+iz+1]&15],G[P[P[P[ix+1]+iy]+iz+1]&15],fs[0]); | |
| t2.Lin3(G[P[P[P[ix]+iy+1]+iz+1]&15],G[P[P[P[ix+1]+iy+1]+iz+1]&15],fs[0]); | |
| t1.Lin3(t1,t2,fs[1]); | |
| t0.Lin3(t0,t1,fs[2]); | |
| #undef ix | |
| #undef iy | |
| #undef iz | |
| #undef P | |
| #undef G | |
| // noise | |
| vert->AddMul3(t0,amp); | |
| } | |
| __asm fldcw [oldcw]; | |
| //#endif | |
| return code; | |
| } | |
| sU32 *GenMesh::RecCopyInner(sU32 *code,sMatrix *matrices,sObject **objects) | |
| { | |
| sU32 count; | |
| GenMesh *srcm; | |
| sVector *src,*dst; | |
| count = *code++; | |
| srcm = (GenMesh *) objects[*code++]; | |
| while(count--) | |
| { | |
| dst = &VertBuf[*code++]; | |
| src = &srcm->VertBuf[*code++]; | |
| sCopyMem4((sU32*)dst,(sU32*)src,*code++ * 4); | |
| } | |
| return code; | |
| } | |
| sU32 *GenMesh::RecF2VNInner(sU32 *code,sMatrix *matrices) | |
| { | |
| sU32 count; | |
| sInt v0,v1,v2; | |
| sInt sn; | |
| sn = VertMap[sGMI_NORMAL]; | |
| count = *code++; | |
| while(count--) | |
| { | |
| v0 = *code++; | |
| v1 = *code++; | |
| v2 = *code++; | |
| CalcNormal(VertBuf[v1+sn],v0,v1,v2); | |
| VertBuf[v1+sn].UnitSafe3(); | |
| } | |
| return code; | |
| } | |
| sU32 *GenMesh::RecEWKInner(sU32 *code,sMatrix *matrices) | |
| { | |
| sInt gcount,count,i; | |
| sF32 ic,dist,vals[3]; | |
| sBool local; | |
| sInt mtx,sn,vs; | |
| sVector *vb,*vd,t,sum; | |
| sMatrix mat; | |
| sn = VertMap[sGMI_NORMAL]; | |
| gcount = *code++; | |
| local = *code++; | |
| mtx = *code++; | |
| vb = VertBuf; | |
| vs = VertSize; | |
| ic = 1.0f / matrices[mtx].j.w; | |
| dist = matrices[mtx].i.w * ic; | |
| for(i=0;i<3;i++) | |
| vals[i] = (&matrices[mtx].j.x)[i] * ic; | |
| mat.InitEulerPI2(vals); | |
| while(gcount--) | |
| { | |
| count = *code++; | |
| // first pass: find middle | |
| sum.Init(0,0,0,0); | |
| if(local) | |
| { | |
| for(i=0;i!=count;i++) | |
| { | |
| vd = VertBuf + code[i]*vs; | |
| sum.x += vd->x + vd[sn].x*dist; | |
| sum.y += vd->y + vd[sn].y*dist; | |
| sum.z += vd->z + vd[sn].z*dist; | |
| } | |
| } | |
| sum.Scale3(1.0f / count); | |
| // second pass: transform | |
| for(i=0;i!=count;i++) | |
| { | |
| vd = VertBuf + code[i]*vs; | |
| t.x = (vd->x + vd[sn].x*dist - sum.x) * matrices[mtx].i.x + sum.x; | |
| t.y = (vd->y + vd[sn].y*dist - sum.y) * matrices[mtx].i.y + sum.y; | |
| t.z = (vd->z + vd[sn].z*dist - sum.z) * matrices[mtx].i.z + sum.z; | |
| vd->Rotate3(mat,t); | |
| vd[sn].Rotate3(mat); | |
| } | |
| code += count; | |
| } | |
| return code; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| 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]; | |
| } | |
| #if !sPLAYER | |
| sInt GenMesh::GetValence(sU32 e) | |
| { | |
| sInt v,k; | |
| sU32 ee; | |
| v = GetVertId(e); k = 0; ee = e; | |
| do | |
| { | |
| if(GetVertId(e)==v) | |
| k++; | |
| e = NextVertEdge(e); | |
| } | |
| while(e!=ee); | |
| return k; | |
| } | |
| sInt GenMesh::GetDegree(sU32 f) | |
| { | |
| sInt e,ee,i; | |
| e = ee = Face[f].Edge; | |
| i = 0; | |
| do | |
| { | |
| i++; | |
| e = NextFaceEdge(e); | |
| } | |
| while(e!=ee); | |
| return i; | |
| } | |
| #endif | |
| 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 dmask1,sU32 dmask0) | |
| { | |
| 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++; | |
| 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(dmask1,dmask0); | |
| 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(dmask1,dmask0); | |
| 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 dmask1,sU32 dmask0) | |
| { | |
| sInt e,p0,p1,n0,n1; | |
| sInt v0,v1,cf,i,lc; | |
| v1 = GetVertId(a); | |
| sVERIFY(Vert[v1].First == GetVert(d)->First); | |
| e = Edge.Count; Edge.AtLeast(e+1); Edge.Count = e+1; | |
| v0 = va; | |
| register GenMeshVert *vert = this->Vert.Array; // AddVert()!!! | |
| vert[v0].Sel(dmask1,dmask0); | |
| vert[v0].First = v0; | |
| vert[v0].Next = v0; | |
| a = a^1; | |
| p0 = PrevFaceEdge(d); | |
| n1 = NextFaceEdge(a); | |
| 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(dmask1,dmask0); | |
| 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(lc); | |
| v1 = AddCopiedVert(v0); | |
| Vert[v1].Sel(dmask1,dmask0); // not register vert!) | |
| Edge[lc/2].Vert[lc&1] = v1; | |
| } | |
| FixVertCycle(e*2); | |
| FixVertCycle(d); | |
| va = GetVertId(e*2); | |
| vb = GetVertId(n1); | |
| } | |
| sInt GenMesh::AddEdge(sInt v0,sInt v1,sInt face) | |
| { | |
| sInt i; | |
| sInt e; | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| if(Edge[i].Face[1]==-1) | |
| { | |
| if(Vert[Edge[i].Vert[0]].First==Vert[v1].First && Vert[Edge[i].Vert[1]].First==Vert[v0].First) | |
| { | |
| Edge[i].Vert[1] = v0; | |
| Edge[i].Face[1] = face; | |
| Face[face].Edge = i*2+1; | |
| return i*2+1; | |
| } | |
| if(Vert[Edge[i].Vert[0]].First==Vert[v1].First && Vert[Edge[i].Vert[1]].First==Vert[v0].First) | |
| { | |
| sVERIFYFALSE; | |
| } | |
| } | |
| } | |
| e = Edge.Count; | |
| Edge.AtLeast(e+1); | |
| Edge.Count = e+1; | |
| Edge[e].Init(); | |
| Edge[e].Vert[0] = v0; | |
| Edge[e].Vert[1] = v1; | |
| Edge[e].Face[0] = face; | |
| Edge[e].Face[1] = -1; | |
| 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<nedges;i++) | |
| { | |
| e=edges[i]; | |
| sVERIFY(Edge[e/2].Face[e&1]==-1 || Face[GetFaceId(e)].Material==0); | |
| Edge[t/2].Next[t&1]=e; | |
| Edge[e/2].Prev[e&1]=t; | |
| Edge[e/2].Face[e&1]=face; | |
| t=e; | |
| } | |
| } | |
| #if !sINTRO | |
| void GenMesh::Verify() | |
| { | |
| sInt i,e,ee; | |
| sInt ec,fc,vc; | |
| ec = Edge.Count*2; | |
| vc = Vert.Count; | |
| fc = Face.Count; | |
| // check face circles | |
| for(i=0;i<fc;i++) | |
| { | |
| if(Face[i].Material==0) | |
| continue; | |
| sVERIFY(Face[i].Edge>=0 && Face[i].Edge<ec); | |
| ee = e = Face[i].Edge; | |
| do | |
| { | |
| sVERIFY(GetFaceId(e)==i); | |
| e = NextFaceEdge(e); | |
| } | |
| while(ee!=e); | |
| ee = e = Face[i].Edge; | |
| do | |
| { | |
| sVERIFY(GetFaceId(e)==i); | |
| e = PrevFaceEdge(e); | |
| } | |
| while(ee!=e); | |
| } | |
| // check vertices | |
| for(i=0;i<vc;i++) | |
| { | |
| sVERIFY(Vert[i].Next>=0 && Vert[i].Next<vc); | |
| sVERIFY(Vert[Vert[i].First].First == Vert[i].First); | |
| } | |
| // check edges | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| sVERIFY(Edge[i].Next[0]>=0 && Edge[i].Next[0]<ec); | |
| sVERIFY(Edge[i].Next[1]>=0 && Edge[i].Next[1]<ec); | |
| sVERIFY(Edge[i].Prev[0]>=0 && Edge[i].Prev[0]<ec); | |
| sVERIFY(Edge[i].Prev[1]>=0 && Edge[i].Prev[1]<ec); | |
| sVERIFY(Edge[i].Face[0]>=0 && Edge[i].Face[0]<fc); | |
| sVERIFY(Edge[i].Face[1]>=0 && Edge[i].Face[1]<fc); | |
| sVERIFY(Edge[i].Vert[0]>=0 && Edge[i].Vert[0]<vc); | |
| sVERIFY(Edge[i].Vert[1]>=0 && Edge[i].Vert[1]<vc); | |
| sVERIFY(GetVert(i*2+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,vc,ec; | |
| vc = Vert.Count; | |
| for(i=0;i<vc;i++) | |
| { | |
| Vert[i].First = Vert[Vert[i].First].ReIndex; | |
| Vert[i].Next = Vert[Vert[i].Next].ReIndex; | |
| } | |
| ec = Edge.Count; | |
| for(i=0;i<ec;i++) | |
| { | |
| Edge[i].Vert[0] = Vert[Edge[i].Vert[0]].ReIndex; | |
| Edge[i].Vert[1] = Vert[Edge[i].Vert[1]].ReIndex; | |
| } | |
| } | |
| sBool GenMesh::IsBorderEdge(sU32 i,sInt mode) | |
| { | |
| sBool s0,s1; | |
| s0 = GetFace(i)->Select; | |
| s1 = GetFaceI(i)->Select; | |
| if((mode==1 && (Edge[i/2].Crease & sGMF_NORMALS)) || mode>=2) | |
| s1 = 0; | |
| return s0 && !s1; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void GenMesh::Mask2Sel(sU32 mask) | |
| { | |
| sInt i; | |
| if(mask&0x00ff0000) | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].Select = ((Vert[i].Mask & (mask>>16))!=0); | |
| if(mask&0x0000ff00) | |
| for(i=0;i<Face.Count;i++) | |
| Face[i].Select = ((Face[i].Mask & (mask>> 8))!=0); | |
| #if !sINTRO_X | |
| if(mask&0x000000ff) | |
| for(i=0;i<Edge.Count;i++) | |
| Edge[i].Select = ((Edge[i].Mask & (mask ))!=0); | |
| #endif | |
| } | |
| void GenMesh::All2Sel(sBool sel) | |
| { | |
| sInt i; | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].Select = sel; | |
| for(i=0;i<Face.Count;i++) | |
| Face[i].Select = sel && Face[i].Material; | |
| #if !sINTRO_X | |
| for(i=0;i<Edge.Count;i++) | |
| Edge[i].Select = sel; | |
| #endif | |
| } | |
| void GenMesh::Id2Mask(sU32 mask,sInt id) | |
| { | |
| #if !sINTRO | |
| sFatal("not implememted"); | |
| #endif | |
| } | |
| void GenMesh::Mask2Mask(sU32 mask,sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i; | |
| if(mask&0x00ff0000) | |
| for(i=0;i<Vert.Count;i++) | |
| if(Vert[i].Mask & (mask>>16)) | |
| Vert[i].Sel(dmask1,dmask0); | |
| if(mask&0x0000ff00) | |
| for(i=0;i<Face.Count;i++) | |
| if(Face[i].Mask & (mask>> 8)) | |
| Face[i].Sel(dmask1,dmask0); | |
| #if !sINTRO_X | |
| if(mask&0x000000ff) | |
| for(i=0;i<Edge.Count;i++) | |
| if(Edge[i].Mask & (mask )) | |
| Edge[i].Sel(dmask1,dmask0); | |
| #endif | |
| } | |
| void GenMesh::Sel2Mask(sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i; | |
| sU32 mask = dmask1|dmask0; | |
| if(mask&0x00ff0000) | |
| for(i=0;i<Vert.Count;i++) | |
| if(Vert[i].Select) | |
| Vert[i].Sel(dmask1,dmask0); | |
| if(mask&0x0000ff00) | |
| for(i=0;i<Face.Count;i++) | |
| if(Face[i].Select) | |
| Face[i].Sel(dmask1,dmask0); | |
| #if !sINTRO_X | |
| if(mask&0x000000ff) | |
| for(i=0;i<Edge.Count;i++) | |
| if(Edge[i].Select) | |
| Edge[i].Sel(dmask1,dmask0); | |
| #endif | |
| } | |
| void GenMesh::All2Mask(sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i; | |
| sU32 mask = dmask1|dmask0; | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(mask&0x00ff0000) | |
| Vert[i].Sel(dmask1,dmask0); | |
| Vert[i].Select = 1; | |
| } | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(!Face[i].Material) | |
| continue; | |
| if(mask&0x0000ff00) | |
| Face[i].Sel(dmask1,dmask0); | |
| Face[i].Select = 1; | |
| } | |
| #if !sINTRO_X | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| if(mask&0x000000ff) | |
| Edge[i].Sel(dmask1,dmask0); | |
| Edge[i].Select = 1; | |
| } | |
| #endif | |
| } | |
| void GenMesh::Face2Vert() | |
| { | |
| sInt i,e,ee; | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].Select = 0; | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(Face[i].Select) | |
| { | |
| e = ee = Face[i].Edge; | |
| do | |
| { | |
| GetVert(e)->Select = 1; | |
| e = NextFaceEdge(e); | |
| } | |
| while(e!=ee); | |
| } | |
| } | |
| } | |
| void GenMesh::Edge2Vert(sInt uvs) | |
| { | |
| sInt i,j; | |
| j = VertMap[sGMI_UV0]; | |
| for(i=0;i<Edge.Count*2;i++) | |
| { | |
| if(Edge[i/2].Select) | |
| { | |
| if((&VertBuf[GetVertId(PrevFaceEdge(i))*VertSize+j].x)[uvs]>0.5f) | |
| { | |
| GetVert(i)->Select=1; | |
| GetVert(NextFaceEdge(i))->Select=1; | |
| } | |
| } | |
| } | |
| } | |
| void GenMesh::SetMaterial(sInt id,GenMaterial *mat) | |
| { | |
| sInt i,o; | |
| sVERIFY(id != 0); | |
| o = Mtrl.Count; | |
| Mtrl.AtLeast(id+1); | |
| for(i=o;i<=id;i++) | |
| Mtrl[i].Init(); | |
| Mtrl.Count = sMax(Mtrl.Count,id+1); | |
| Mtrl[id].Material = mat; | |
| for(i=0;i<GENMAT_MAXPASS;i++) | |
| Mtrl[id].Pass[i].Reset(); | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(Face[i].Select) | |
| Face[i].Material = id; | |
| } | |
| } | |
| sInt GenMesh::FindCrease(sInt edge,sInt mask) | |
| { | |
| sInt ee; | |
| ee = edge; | |
| do | |
| { | |
| if(Edge[edge/2].Crease & mask) | |
| ee = edge; | |
| else | |
| edge = PrevVertEdge(edge); | |
| } | |
| while(ee!=edge); | |
| return edge; | |
| } | |
| void GenMesh::CalcNormal(sVector &n,sInt o0,sInt o1,sInt o2) | |
| { | |
| sVector t1,t2; | |
| t1.Sub3(VertBuf[o1],VertBuf[o0]); | |
| t2.Sub3(VertBuf[o2],VertBuf[o0]); | |
| n.Cross3(t1,t2); | |
| } | |
| void GenMesh::CalcFaceNormal(sVector &n,sInt f) | |
| { | |
| sInt e; | |
| e = Face[f].Edge; | |
| CalcNormal(n,GetVertId(PrevFaceEdge(e))*VertSize,GetVertId(e)*VertSize, | |
| GetVertId(NextFaceEdge(e))*VertSize); | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| void GenMesh::TransVert(sMatrix &mat,sInt sj,sInt djj) | |
| { | |
| sU32 *data; | |
| sInt i,dj; | |
| sj = VertMap[sj]; if(sj==-1) return; | |
| dj = VertMap[djj&0x0f]; if(dj==-1) return; | |
| dj |= djj&0x10; | |
| data = RecBegin(IM_XFORM); | |
| *data++ = sj; | |
| *data++ = dj; | |
| *data++ = RecMatrix(mat); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Select) | |
| { | |
| *data++ = i; | |
| RecOpCount++; | |
| } | |
| } | |
| RecEnd(data); | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::SelectCube(const sVector &vc,const sVector &vs,sBool set,sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i,e,ee; | |
| sBool all; | |
| sVERIFY(RecMode==0); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| Vert[i].Temp = 0; | |
| if(sFAbs(VertPos(i).x-vc.x)<=vs.x && | |
| sFAbs(VertPos(i).y-vc.y)<=vs.y && | |
| sFAbs(VertPos(i).z-vc.z)<=vs.z) | |
| { | |
| Vert[i].Sel(dmask1,dmask0); | |
| Vert[i].Select = 1; | |
| Vert[i].Temp = 1; | |
| } | |
| else if(set) | |
| { | |
| Vert[i].Sel(0,dmask1); | |
| Vert[i].Select = 0; | |
| } | |
| } | |
| #if !sINTRO_X | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| if(Vert[Edge[i].Vert[0]].Temp && Vert[Edge[i].Vert[1]].Temp) | |
| { | |
| Edge[i].Sel(dmask1,dmask0); | |
| Edge[i].Select = 1; | |
| } | |
| else if(set) | |
| { | |
| Edge[i].Sel(0,dmask1); | |
| Edge[i].Select = 0; | |
| } | |
| } | |
| #endif | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(!Face[i].Material) | |
| continue; | |
| e = ee = Face[i].Edge; | |
| all = sTRUE; | |
| do | |
| { | |
| if(!GetVert(e)->Temp) | |
| all = 0; | |
| e = NextFaceEdge(e); | |
| } | |
| while(ee!=e && all); | |
| if(all) | |
| { | |
| Face[i].Sel(dmask1,dmask0); | |
| Face[i].Select = 1; | |
| } | |
| else if(set) | |
| { | |
| Face[i].Sel(0,dmask1); | |
| Face[i].Select = 0; | |
| } | |
| } | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::Ring(sInt count,sU32 dmask,sF32 radius,sF32 phase) | |
| { | |
| sInt i,in,ip; | |
| sInt sj; | |
| sVector *vp; | |
| GenMeshEdge *ed; | |
| sVERIFY(RecMode==0); | |
| 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;i<count;i++) | |
| { | |
| AddNewVert(); | |
| vp = &VertBuf[i*VertSize]; | |
| vp->x = sFSin(phase+i*sPI2F/count)*radius; | |
| vp->y = -sFCos(phase+i*sPI2F/count)*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); | |
| All2Sel(0); | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::Extrude(sU32 dmask1,sU32 dmask0,sInt mode) | |
| { | |
| sInt i,e,ee; | |
| sInt ec,fc; | |
| sU32 i0,i1,*data; | |
| sInt f,va,vb; | |
| RecBegin(IM_ADDSCL); | |
| ec = Edge.Count; | |
| fc = Face.Count; | |
| for(i=0;i<ec*2;i++) | |
| { | |
| Edge[i/2].Temp[i&1] = -1; | |
| if(IsBorderEdge(i,mode)) | |
| { | |
| Edge[i/2].Temp[i&1] = 0; | |
| e = i; | |
| do | |
| { | |
| e = NextVertEdge(e); | |
| } | |
| while(!IsBorderEdge(e^1,mode)); | |
| va = AddCopiedVert(GetVertId(i)); | |
| SplitBridge(e,i,va,vb,dmask1,dmask0); | |
| RecAddScale(va,1,RM_ALL,GetVertId(i),1.0f); | |
| } | |
| } | |
| for(i=0;i<ec*2;i++) | |
| { | |
| if(!Edge[i/2].Temp[i&1]) | |
| { | |
| i0 = PrevFaceEdge(i); | |
| i1 = NextFaceEdge(i); | |
| i1 = NextFaceEdge(i1); | |
| f = Face.Count; | |
| SplitFace(i1,i0,dmask1,dmask0); | |
| Face[f].Select = 0; | |
| } | |
| } | |
| RecEnd(); | |
| if(mode==3) | |
| { | |
| data = RecBegin(IM_F2VN); | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(Face[i].Select) | |
| { | |
| e = ee = Face[i].Edge; | |
| do | |
| { | |
| RecOpCount++; | |
| *data++ = GetVertId(PrevFaceEdge(e)) * VertSize; | |
| *data++ = GetVertId(e) * VertSize; | |
| *data++ = GetVertId(NextFaceEdge(e)) * VertSize; | |
| e = NextFaceEdge(e); | |
| } | |
| while(e!=ee); | |
| } | |
| } | |
| RecEnd(data); | |
| } | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::Subdivide(sF32 alpha) | |
| { | |
| sInt i,j,k,count,e,ee,c,v,vv; | |
| sInt va0,va1,vb0,vb1,va,vb; | |
| sInt ec,fc,ovc; | |
| sInt s0,s1; | |
| sU32 Temp[64*2+2]; | |
| sF32 ftemp; | |
| fc = Face.Count; | |
| RecBegin(IM_ADDSCL); | |
| ovc = Vert.Count; | |
| // 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 | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| Vert[i].Temp = -1; | |
| Vert[i].ReIndex = i; | |
| } | |
| // calculate center positions | |
| fc = Face.Count; | |
| for(i=0;i<fc;i++) | |
| { | |
| Face[i].Temp = -1; | |
| Face[i].Temp2 = -1; | |
| if(Face[i].Select) | |
| { | |
| count=0; | |
| ee = e = Face[i].Edge; | |
| do | |
| { | |
| v = GetVertId(e); | |
| Temp[count*2]=v; | |
| if (Vert[v].Temp == -1) | |
| { | |
| vv = AddCopiedVert(v); | |
| Vert[v].Temp = vv; | |
| Vert[v].Temp2 = e; | |
| Vert[v].ReIndex = vv; | |
| } | |
| e = NextFaceEdge(e); | |
| count++; | |
| } while (e != ee); | |
| Face[i].Temp2 = c = AddNewVert(); | |
| Vert[c].Select = 1; | |
| ftemp = 1.0f/count; | |
| for(j=0;j<count;j++) | |
| Temp[j*2+1] = *((sU32*) &ftemp); | |
| RecAddScaleArray(c,count,RM_POS|RM_REST,Temp); | |
| } | |
| } | |
| // even vertices | |
| alpha *= 4.0f; | |
| for(i=0;i<ovc;i++) | |
| { | |
| if(Vert[i].Temp!=-1) | |
| { | |
| vv = Vert[i].Temp; | |
| k = 0; | |
| ee = Vert[i].Temp2; | |
| e = ee; | |
| ec = 0; // edge crease flags | |
| c = -1; | |
| do | |
| { | |
| Temp[k*2] = GetVertId(e^1); | |
| k++; | |
| if(GetFace(e)->Temp2!=-1) | |
| { | |
| Temp[k*2] = GetFace(e)->Temp2; | |
| k++; | |
| } | |
| else | |
| c = e; | |
| if (GetVertId(e) == i) | |
| ec |= Edge[e/2].Crease; | |
| e = NextVertEdge(e); | |
| } | |
| while (ee != e); | |
| if(c==-1) | |
| { | |
| ftemp = alpha / (k * k); | |
| for (j=0;j<k;j++) | |
| Temp[j*2+1] = *((sU32*) &ftemp); | |
| Temp[k*2] = i; | |
| ftemp = (k - alpha) / k; | |
| Temp[k*2+1] = *((sU32*) &ftemp); | |
| RecAddScaleArray(vv,k+1,~ec & ~RM_NORMAL,Temp); | |
| RecAddScale(vv,1,ec & ~RM_NORMAL,i,1.0f); | |
| } | |
| else | |
| { | |
| va = GetVertId(c^1); | |
| do | |
| { | |
| c = NextVertEdge(c); | |
| } | |
| while (GetFaceI(c)->Temp2!=-1); | |
| vb = GetVertId(c^1); | |
| ftemp = alpha/32.0f; | |
| RecAddScale(vv,3,RM_POS|RM_REST,i,1.0f-2.0f*ftemp,va,ftemp,vb,ftemp); | |
| } | |
| } | |
| } | |
| // split edges | |
| alpha /= 16.0f; | |
| ftemp = 0.5f - alpha; | |
| ec = Edge.Count; | |
| for(i=0;i<ec*2;i+=2) | |
| { | |
| // calc center position | |
| va0 = GetVertId(i); | |
| va1 = GetVertId(NextFaceEdge(i)); | |
| vb1 = GetVertId(i^1); | |
| vb0 = GetVertId(NextFaceEdge(i^1)); | |
| // split if select | |
| s0 = GetFace(i)->Select; | |
| s1 = GetFaceI(i)->Select; | |
| if(s0 || s1) | |
| { | |
| // split edge | |
| va = AddNewVert(); | |
| SplitBridge(NextVertEdge(i^1),PrevVertEdge(i^1),va,vb,0x100000,0); | |
| // calc position | |
| if(GetFace(i)->Temp2==-1 || GetFaceI(i)->Temp2==-1) | |
| { | |
| RecAddScale(va,2,RM_POS|RM_REST,va0,0.5f,va1,0.5f); | |
| if (va != vb) | |
| RecAddScale(vb,2,RM_POS|RM_REST,vb0,0.5f,vb1,0.5f); | |
| } | |
| else | |
| { | |
| if(va != vb) | |
| { | |
| j = Edge[i/2].Crease; // mask out pos | |
| RecAddScale(va,4,~j & ~RM_NORMAL,va0,ftemp,va1,ftemp, | |
| Face[Edge[i/2].Face[0]].Temp2,alpha,Face[Edge[i/2].Face[1]].Temp2,alpha); | |
| RecAddScale(va,2,j & ~RM_NORMAL,va0,0.5f,va1,0.5f); | |
| RecAddScale(vb,4,~j & ~RM_NORMAL,vb0,ftemp,vb1,ftemp, | |
| Face[Edge[i/2].Face[0]].Temp2,alpha,Face[Edge[i/2].Face[1]].Temp2,alpha); | |
| RecAddScale(vb,2,j & ~RM_NORMAL,vb0,0.5f,vb1,0.5f); | |
| } | |
| else | |
| { | |
| RecAddScale(va,4,RM_POS|RM_REST,va0,ftemp,va1,ftemp, | |
| Face[Edge[i/2].Face[0]].Temp2,alpha,Face[Edge[i/2].Face[1]].Temp2,alpha); | |
| } | |
| } | |
| // 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;i<fc;i++) | |
| { | |
| if(Face[i].Select && Face[i].Material!=0) | |
| { | |
| sVERIFY(Face[i].Temp!=-1); | |
| sVERIFY(Face[i].Temp2!=-1); | |
| e = Face[i].Temp; | |
| count=0; | |
| ee = e; | |
| do | |
| { | |
| ee = NextFaceEdge(ee); | |
| sVERIFY(count<64); | |
| Temp[count++] = ee; | |
| ee = NextFaceEdge(ee); | |
| } | |
| while(e!=ee); | |
| va = Face[i].Temp2; | |
| SplitBridge(NextVertEdge(Temp[0]),Temp[0],va,vb,0,0); | |
| for(j=1;j<count;j++) | |
| SplitFace(PrevFaceEdge(PrevFaceEdge(PrevFaceEdge(Temp[j]))),Temp[j]); | |
| } | |
| } | |
| ReIndex(); | |
| RecEnd(); | |
| } | |
| /****************************************************************************/ | |
| sInt GenMesh::Bones(sF32 phase) | |
| { | |
| sU32 *data; | |
| sF32 wgt; | |
| sInt i,j,mi,lm=0; | |
| data = RecBegin(IM_BONE); | |
| sVERIFY(RBIndex+BoneMatrix.Count<1024); | |
| BonesModify(-1,phase); | |
| mi = RBIndex; | |
| RBIndex += BoneMatrix.Count; | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Matrix[0]!=0xff) | |
| { | |
| RecOpCount++; | |
| *data++ = i * VertSize; | |
| for(j=0;j<4;j++) | |
| { | |
| if(Vert[i].Matrix[j]!=0xff) | |
| { | |
| wgt = Vert[i].Weight[j] / 255.0f; | |
| lm = Vert[i].Matrix[j] + mi; | |
| } | |
| else | |
| wgt = 0.0f; | |
| *data++ = *((sU32 *) &wgt); | |
| *data++ = lm; | |
| } | |
| } | |
| } | |
| RecEnd(data); | |
| return mi; | |
| } | |
| void GenMesh::BonesModify(sInt matrix,sF32 phase) | |
| { | |
| sMatrix *mp; | |
| sInt i; | |
| sInt ki0,ki1; | |
| sF32 f1,val; | |
| sMatrix mat; | |
| GenMeshCurve *cur; | |
| if(matrix<0) | |
| { | |
| mp = &RBMat[RBIndex]; | |
| sVERIFY(CurveCount==BoneCurve.Count) | |
| } | |
| else | |
| { | |
| mp = &RecMat.Array[matrix]; | |
| sVERIFY(matrix+BoneMatrix.Count <= RecMat.Count); | |
| } | |
| if(KeyCount>0 && 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;i<BoneCurve.Count;i++) | |
| { | |
| val = KeyBuf[i*KeyCount+ki0] + (KeyBuf[i*KeyCount+ki1]-KeyBuf[i*KeyCount+ki0]) * f1; | |
| BoneMatrix[cur->Matrix].TransSRT[cur->Curve] = val; | |
| cur++; | |
| } | |
| } | |
| BoneMatrix[0].Matrix.InitSRT(BoneMatrix[0].TransSRT); | |
| mat.InitSRTInv(BoneMatrix[0].BaseSRT); | |
| mp[0].Mul4(mat,BoneMatrix[0].Matrix); | |
| for(i=1;i<BoneMatrix.Count;i++) | |
| { | |
| mat.InitSRT(BoneMatrix[i].TransSRT); | |
| BoneMatrix[i].Matrix.Mul4(mat,BoneMatrix[BoneMatrix[i].Parent].Matrix); | |
| mat.InitSRTInv(BoneMatrix[i].BaseSRT); | |
| mp[i].Mul4(mat,BoneMatrix[i].Matrix); | |
| } | |
| for(i=0;i<BoneMatrix.Count;i++) | |
| { | |
| mp[i].i.z = -mp[i].i.z; | |
| mp[i].j.z = -mp[i].j.z; | |
| mp[i].k.z = -mp[i].k.z; | |
| mp[i].l.z = -mp[i].l.z; | |
| } | |
| } | |
| /****************************************************************************/ | |
| void GenMesh::FixVertCycle(sInt i) | |
| { | |
| sInt v,v0,vn,e; | |
| v0 = v = GetVertId(i); | |
| Vert[v].First = v0; | |
| Vert[v].Next = v0; | |
| e = i; | |
| do | |
| { | |
| Edge[e/2].Vert[e&1] = v; | |
| e = NextVertEdge(e); | |
| vn = GetVertId(e); | |
| if(Edge[e/2].Crease && vn!=v) | |
| { | |
| Vert[v].Next = vn; | |
| v = vn; | |
| Vert[v].First = v0; | |
| Vert[v].Next = v0; | |
| } | |
| } | |
| while(e!=i); | |
| } | |
| void GenMesh::SingleCrease(sU32 i,sU32 dmask1,sU32 dmask0,sInt what) | |
| { | |
| sInt j,k,e,got,v0,v,vf; | |
| sVERIFY(!(what & 1)); | |
| 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(dmask1,dmask0); | |
| Vert[v].First = vf; | |
| Vert[v0].Next = v; | |
| RecAddScale(v,1,RM_ALL,v0,1.0f); | |
| 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::Crease(sInt selType,sU32 dmask1,sU32 dmask0,sInt what) | |
| { | |
| sInt i; | |
| sBool sel; | |
| RecBegin(IM_ADDSCL); | |
| for(i=0;i<Edge.Count*2;i++) | |
| { | |
| if(selType==0) | |
| sel = IsBorderEdge(i,0); | |
| else if(selType==1) | |
| sel = Edge[i/2].Select; | |
| else | |
| sel = GetFace(i)->Select; | |
| if(sel) | |
| SingleCrease(i,dmask1,dmask0,what); | |
| } | |
| RecEnd(); | |
| } | |
| void GenMesh::UnCrease(sBool edge,sInt what) | |
| { | |
| sInt i; | |
| sBool sel; | |
| sVERIFY(!(what & 1)); | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| if(edge) | |
| sel = Edge[i].Select; | |
| else | |
| sel = IsBorderEdge(i*2,0); | |
| if(sel) | |
| Edge[i].Crease &= ~what; | |
| } | |
| // todo: fix vertices too | |
| } | |
| void GenMesh::CalcNormals(sInt type,sInt calcWhat) | |
| { | |
| sU32 *data; | |
| sInt i,vs,e,pe,ee,count,msk; | |
| sBool ok; | |
| msk = type ? 0 : sGMF_NORMAL; | |
| vs = VertSize * sizeof(sVector); | |
| data = RecBegin(IM_NORMAL); | |
| // first build vertex->edge links in Temp | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].Temp = -1; | |
| for(i=0;i<Edge.Count*2;i++) | |
| Vert[GetVertId(i)].Temp = i; | |
| // write data. format: count, face offsets, dest vertex offset. | |
| *data++ = calcWhat; | |
| if(calcWhat) | |
| { | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| count = 0; | |
| if(Vert[i].Temp==-1) | |
| continue; | |
| // find "left border" (finds a crease or just a full loop) | |
| e = ee = FindCrease(Vert[i].Temp,msk); | |
| ok = sFALSE; | |
| // add all vertices on this side of the crease | |
| do | |
| { | |
| if(GetFace(e)->Select) | |
| ok = sTRUE; | |
| data[++count + 1] = GetVertId(e) * vs; | |
| data[++count + 1] = GetVertId(e^1) * vs; | |
| e = NextVertEdge(e); | |
| pe = e; | |
| } | |
| while(e != ee && !(Edge[pe/2].Crease & msk)); | |
| data[++count + 1] = GetVertId(e) * vs; | |
| data[++count + 1] = GetVertId(e^1) * vs; | |
| if(ok) | |
| { | |
| RecOpCount++; | |
| *data = count/2; | |
| data[1] = i * vs; | |
| data += count + 2; | |
| } | |
| } | |
| } | |
| RecEnd(data); | |
| } | |
| void GenMesh::Triangulate(sInt threshold,sU32 dmask1,sU32 dmask0,sInt type) | |
| { | |
| sInt i,j,c,v,e,ee; | |
| sInt Edgei[64]; | |
| sU32 Temp[128]; | |
| sF32 ftemp; | |
| if(!type) | |
| RecBegin(IM_ADDSCL); | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(Face[i].Select) | |
| { | |
| e = ee = Face[i].Edge; | |
| c = 0; | |
| do | |
| { | |
| sVERIFY(c < 64); | |
| Edgei[c] = e; | |
| Temp[c*2] = GetVertId(e); | |
| e = NextFaceEdge(e); | |
| c++; | |
| } | |
| while(e != ee); | |
| if(c>=threshold) | |
| { | |
| if(!type) | |
| { | |
| v = AddNewVert(); | |
| Vert[v].Sel(dmask1,dmask0); | |
| ftemp = 1.0f / c; | |
| for(j=0;j<c;j++) | |
| { | |
| Temp[j*2+1] = *((sU32 *) &ftemp); | |
| if(j==0) | |
| SplitBridge(NextVertEdge(Edgei[0]),Edgei[0],v,e,dmask1,dmask0); | |
| else | |
| SplitFace(PrevFaceEdge(PrevFaceEdge(Edgei[j])),Edgei[j],dmask1,dmask0); | |
| } | |
| RecAddScaleArray(v,c,RM_ALL,Temp); | |
| } | |
| else | |
| { | |
| for(j=0;j<c-3;j++) | |
| SplitFace(PrevFaceEdge(PrevFaceEdge(Edgei[j])),Edgei[j],dmask1,dmask0); | |
| } | |
| } | |
| } | |
| } | |
| if(!type) | |
| RecEnd(); | |
| } | |
| void GenMesh::Cut(const sVector &plane,sInt mode) | |
| { | |
| sInt i,va0,va1,vb0,vb1,ec,va,vb,e,ee,pe,noe,noet; | |
| sF32 t0,t1; | |
| sBool force; | |
| RecBegin(IM_ADDSCL); | |
| // classify vertices | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| t0 = VertPos(i).Dot3(plane)+plane.w; | |
| Vert[i].Temp = *((sU32 *) &t0); | |
| } | |
| // clip edges | |
| ec = Edge.Count; | |
| for(i=0;i<ec*2;i+=2) | |
| { | |
| va0 = GetVertId(i); | |
| va1 = GetVertId(NextFaceEdge(i)); | |
| vb1 = GetVertId(i^1); | |
| vb0 = GetVertId(NextFaceEdge(i^1)); | |
| if ((Vert[va0].Temp ^ Vert[vb1].Temp) < 0) // edge crosses plane? | |
| { | |
| t0 = *((sF32 *) &Vert[va0].Temp); | |
| t1 = *((sF32 *) &Vert[vb1].Temp) - t0; | |
| if (fabs(t1) > 1e-5f) // avoid precision problems | |
| { | |
| va = AddNewVert(); | |
| SplitBridge(NextFaceEdge(i^1),PrevFaceEdge(i^1),va,vb); | |
| t0 = -t0 / t1; | |
| RecAddScale(va,2,RM_ALL,va0,1.0f-t0,va1,t0); | |
| Vert[va].Temp = 0; | |
| if(va!=vb) | |
| { | |
| RecAddScale(vb,2,RM_ALL,vb0,1.0f-t0,vb1,t0); | |
| Vert[vb].Temp = 0; | |
| } | |
| } | |
| } | |
| } | |
| for(i=0;i<Edge.Count*2;i+=2) | |
| { | |
| GetEdge(i)->Temp[0] = GetVert(i)->Temp >= 0 && GetVert(i^1)->Temp >= 0; | |
| GetEdge(i)->Temp[1] = 0; | |
| } | |
| // fix faces | |
| noe = 0; | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| ec = 0; | |
| e = Face[i].Edge; | |
| ee = PrevFaceEdge(e); | |
| pe = -1; | |
| do | |
| { | |
| force = sFALSE; | |
| if(GetEdge(e)->Temp[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(i<Edge.Count); | |
| // prepare new face | |
| Face.AtLeast(Face.Count+1); | |
| Face[Face.Count].Init(); | |
| Face[Face.Count].Edge = i*2+1; | |
| Face[Face.Count].Material = mode ? Face[Edge[i].Face[0]].Material : 0; | |
| Face.Count++; | |
| e = ee = i*2+1; | |
| // add open edges till face is closed | |
| do | |
| { | |
| GetEdge(e)->Temp[1] = 0; | |
| sVERIFY(noe>0); | |
| noe--; | |
| for(i=(Edge.Count-noet)*2;i<Edge.Count*2;i++) | |
| { | |
| if((GetEdge(i)->Temp[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); | |
| } | |
| RecEnd(); | |
| 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;i<Edge.Count;i++) | |
| Edge[i].Used = 0; | |
| // mark+renumber faces | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if (Face[i].Material != -1) | |
| { | |
| e = ee = Face[i].Edge; | |
| do | |
| { | |
| Edge[e/2].Used = 1; | |
| e = NextFaceEdge(e); | |
| } | |
| while(e != ee); | |
| remapf[i] = fc; | |
| Face[fc] = Face[i]; | |
| fc++; | |
| } | |
| } | |
| // mark+renumber edges | |
| for(i=0;i<Edge.Count;i++) | |
| { | |
| if(Edge[i].Used) | |
| { | |
| remape[i] = ec*2; | |
| Edge[ec] = Edge[i]; | |
| ec++; | |
| } | |
| } | |
| Face.Count = fc; | |
| Edge.Count = ec; | |
| // fix links | |
| for(i=0;i<ec;i++) | |
| { | |
| for(j=0;j<4;j++) | |
| { | |
| e = Edge[i].Next[j]; | |
| Edge[i].Next[j] = remape[e/2] | (e&1); | |
| } | |
| for(j=0;j<2;j++) | |
| Edge[i].Face[j] = remapf[Edge[i].Face[j]]; | |
| } | |
| for(i=0;i<fc;i++) | |
| { | |
| e = Face[i].Edge; | |
| Face[i].Edge = remape[e/2] | (e&1); | |
| } | |
| delete[] remape; | |
| delete[] remapf; | |
| } | |
| void GenMesh::ExtrudeNormal(sF32 distance) | |
| { | |
| sMatrix mat; | |
| mat.Init(); | |
| mat.i.x = distance; | |
| mat.j.y = distance; | |
| mat.k.z = distance; | |
| TransVert(mat,sGMI_NORMAL,sGMI_POS+0x10); | |
| /* | |
| sInt i; | |
| sU32 *data; | |
| data = RecBegin(IM_ADDSCL); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Select) | |
| { | |
| *data++ = 2; | |
| data = RecSourceInd(data,i*VertSize); | |
| *data++ = 0x3f800000; // 1.0f | |
| data = RecSourceInd(data,i*VertSize+VertMap[sGMI_NORMAL]); | |
| *data++ = *(sU32 *)&distance; | |
| data = RecDestInd(data,i*VertSize); | |
| RecOpCount++; | |
| } | |
| } | |
| RecEnd(data); | |
| */ | |
| } | |
| #if !sINTRO_X | |
| void GenMesh::Displace(GenBitmap *bitmap,sF32 amplitude) | |
| { | |
| sInt i; | |
| sU32 *data; | |
| data = RecBegin(IM_DISPLACE); | |
| *data++ = RecObject(bitmap); | |
| *data++ = *((sU32 *) &litude); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Select) | |
| { | |
| *data++ = i * VertSize; | |
| RecOpCount++; | |
| } | |
| } | |
| RecEnd(data); | |
| } | |
| #endif | |
| #if !sINTRO_X | |
| void GenMesh::Bevel(sF32 elevate,sF32 pullin,sInt mode,sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i,v,vf,vn,e; | |
| sU32 *data; | |
| Extrude(dmask1,dmask0,mode); | |
| data = RecBegin(IM_BEVEL); | |
| *((sF32 *) data) = pullin; data++; | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].ReIndex=i; | |
| for(i=0;i<Edge.Count*2;i++) | |
| Edge[i/2].Temp[i&1] = IsBorderEdge(i,mode) ? 0 : -1; | |
| for(i=0;i<Edge.Count*2;i++) | |
| { | |
| if(Edge[i/2].Temp[i&1]!=-1) | |
| { | |
| e=i; | |
| do | |
| { | |
| e=PrevVertEdge(e); | |
| sVERIFY(e!=i); | |
| } | |
| while(Edge[e/2].Temp[~e&1]==-1); | |
| Edge[i/2].Temp[i&1]=e^1; | |
| } | |
| } | |
| for(i=0;i<Edge.Count*2;i++) | |
| { | |
| e=Edge[i/2].Temp[i&1]; | |
| if(e!=-1) | |
| { | |
| sVERIFY(Edge[e/2].Temp[e&1]!=-1); | |
| v = vf = GetVertId(e); | |
| do | |
| { | |
| *data++ = GetVertId(i); | |
| *data++ = v; | |
| *data++ = GetVertId(Edge[e/2].Temp[e&1]); | |
| Vert[v].ReIndex = vn = AddCopiedVert(v); | |
| *data++ = vn; | |
| RecOpCount++; | |
| v = Vert[v].Next; | |
| } | |
| while (mode==1 && v!=vf); | |
| } | |
| } | |
| RecEnd(data); | |
| ReIndex(); | |
| Face2Vert(); | |
| ExtrudeNormal(elevate); | |
| } | |
| #endif | |
| void GenMesh::Perlin(const sMatrix &mat,const sVector &) | |
| { | |
| //#if !sINTRO_X | |
| sInt i; | |
| sU32 *data; | |
| sMatrix ampmat; | |
| data = RecBegin(IM_PERLIN); | |
| *data++ = RecMatrix(mat); | |
| ampmat.Init(); | |
| ampmat.i = amp; | |
| RecMatrix(ampmat); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Select) | |
| { | |
| *data++ = i; | |
| RecOpCount++; | |
| } | |
| } | |
| RecEnd(data); | |
| //#endif | |
| } | |
| sBool GenMesh::Add(GenMesh *other) | |
| { | |
| sInt i,j,v,e,f,m; | |
| GenMeshVert *vp; | |
| GenMeshEdge *ep; | |
| GenMeshFace *fp; | |
| GenMeshMtrl *mp; | |
| sU32 *data; | |
| if(VertMask!=other->VertMask) | |
| return sFALSE; | |
| // add topological info | |
| 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-1; Mtrl.AtLeast(m+other->Mtrl.Count); Mtrl.Count+=other->Mtrl.Count-1; | |
| Realloc(v+other->Vert.Count); | |
| vp = &Vert[v]; | |
| for(i=0;i<other->Vert.Count;i++,vp++) | |
| { | |
| *vp=other->Vert[i]; | |
| vp->Next+=v; | |
| vp->First+=v; | |
| } | |
| ep = &Edge[e]; | |
| for(i=0;i<other->Edge.Count;i++,ep++) | |
| { | |
| *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; | |
| } | |
| } | |
| fp = &Face[f]; | |
| for(i=0;i<other->Face.Count;i++,fp++) | |
| { | |
| *fp=other->Face[i]; | |
| fp->Edge+=e*2; | |
| fp->Material = fp->Material ? fp->Material+m : 0; | |
| } | |
| mp = &Mtrl[m+1]; | |
| for(i=1;i<other->Mtrl.Count;i++,mp++) | |
| { | |
| *mp=other->Mtrl[i]; | |
| for(j=0;j<GENMAT_MAXBATCH;j++) | |
| mp->Pass[j].Reset(); | |
| } | |
| // add vert buffers | |
| data = RecBegin(IM_COPY); | |
| *data++ = RecObject(other); | |
| *data++ = v * VertSize; // dest | |
| *data++ = 0; // start | |
| *data++ = other->Vert.Count * VertSize; | |
| RecOpCount++; | |
| RecEnd(data); | |
| return sTRUE; | |
| } | |
| void GenMesh::DeleteFaces() | |
| { | |
| sInt i; | |
| for(i=0;i<Face.Count;i++) | |
| { | |
| if(Face[i].Select) | |
| { | |
| Face[i].Material=0; | |
| Face[i].Select=0; | |
| Face[i].Mask=0; | |
| } | |
| } | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| static sF32 fget(sU8 *ptr) | |
| { | |
| sU16 v; | |
| sU32 vd; | |
| v = *(sU16 *) ptr; | |
| vd = (v & 32768) << 16 // sign | |
| | ((((v >> 10) & 31) + 128 - 16) << 23) | |
| | ((v & 1023) << 13); | |
| return *(sF32 *) &vd; | |
| } | |
| #if !sINTRO | |
| static sInt doShift(sU32 v,sInt shift) | |
| { | |
| while(shift>0) | |
| v<<=1,shift--; | |
| while(shift<0) | |
| v>>=1,shift++; | |
| return v; | |
| } | |
| static sF32 fput(sF32 v,sU8 *ptr) | |
| { | |
| sU32 value; | |
| sU16 dest; | |
| sInt esrc,edst; | |
| value = *(sU32 *) &v; | |
| esrc = ((value>>23) & 255) - 128; | |
| edst = sRange(esrc,15,-16); | |
| dest = ((value>>16) & 32768) // sign | |
| | ((edst+16)<<10) | |
| | (doShift(value>>13,edst-esrc) & 1023); | |
| *(sU16 *) ptr = dest; | |
| return fget((sU8 *) &dest); | |
| } | |
| struct fwrite | |
| { | |
| sF32 min; | |
| sF32 max; | |
| void Init(sF32); | |
| void Pre(sF32); | |
| void Write0(sU8 *&p); | |
| void Write(sU8 *&p,sF32); | |
| }; | |
| void fwrite::Init(sF32 f) | |
| { | |
| min = max = f; | |
| } | |
| void fwrite::Pre(sF32 f) | |
| { | |
| if(f<min) | |
| min = f; | |
| if(f>max) | |
| max = f; | |
| } | |
| void fwrite::Write0(sU8 *&p) | |
| { | |
| if(min+0.125f>=max) | |
| max=min+0.125f; | |
| min = fput(min,p); p+=2; | |
| max = fput(max,p); p+=2; | |
| } | |
| void fwrite::Write(sU8 *&p,sF32 f) | |
| { | |
| *p++ = sRange<sInt>((f-min)/(max-min)*255,255,0); | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| class MeshElement | |
| { | |
| public: | |
| sInt Degree; | |
| sInt Temp; | |
| MeshElement **Elem; | |
| static sU32 *Storage; | |
| void Init(sInt deg); | |
| sInt Find(MeshElement *v,sInt adj) const; | |
| static void ResetStorage(); | |
| }; | |
| sU32 *MeshElement::Storage; | |
| void MeshElement::Init(sInt deg) | |
| { | |
| Degree = deg; | |
| Elem = (MeshElement **) Storage; | |
| Storage += deg; | |
| } | |
| sInt MeshElement::Find(MeshElement *v,sInt adj) const | |
| { | |
| sInt i; | |
| MeshElement **ep; | |
| ep = Elem; | |
| for(i=0;i<Degree;i++) | |
| { | |
| if(ep[i]==v) | |
| return (i+adj+Degree)%Degree; | |
| } | |
| sVERIFYFALSE; | |
| return 0; | |
| } | |
| void MeshElement::ResetStorage() | |
| { | |
| Storage = RBData; | |
| sSetMem4(RBData,0,RBCOUNTMAX); | |
| } | |
| class MeshCoder | |
| { | |
| public: | |
| MeshElement *Face; | |
| sInt FaceCtr; | |
| MeshElement *Vert; | |
| sInt VertCtr; | |
| GenMesh *Mesh; | |
| #if !sPLAYER | |
| sInt VertOrder[65536],VertPos; | |
| #endif | |
| sInt FaceCount; | |
| RangeCoder Coder; | |
| RangeModel DV; | |
| RangeModel DVFlag; | |
| sInt avList[256],avPos; | |
| #if !sPLAYER | |
| void Encode(GenMesh *msh,sU8 *&p); | |
| sInt NextVertSlot(sInt e); | |
| sInt FindFirstVert(sInt v); | |
| GenMesh *MakeClosedMesh(GenMesh *msh); | |
| void ActivateVE(MeshElement *f,sInt i,sInt edg); | |
| MeshElement *AddFace(sInt deg); | |
| MeshElement *AddVert(sInt deg); | |
| #endif | |
| sU8 *Decode(GenMesh *msh,sU8 *p); | |
| MeshElement *DecodeFace(); | |
| void ActivateVD(MeshElement *f,sInt i); | |
| sInt ForceFV(MeshElement *f,sInt j,sInt dir); | |
| void AddFaceToVertex(MeshElement *f,sInt i,MeshElement *v,sInt j); | |
| }; | |
| #define sDV_LOWRANGE 9 // fine-tune this for some additional bytes :) | |
| #if !sPLAYER | |
| void MeshCoder::Encode(GenMesh *msh,sU8 *&p) | |
| { | |
| sInt i,il,j,k,e,ee,seed,vi,d; | |
| MeshElement *f,*v; | |
| Mesh = MakeClosedMesh(msh); | |
| MeshElement::ResetStorage(); | |
| Face = new MeshElement[Mesh->Face.Count]; | |
| Vert = new MeshElement[Mesh->Vert.Count]; | |
| FaceCtr = 0; | |
| VertCtr = 0; | |
| avPos = 0; | |
| for(i=0;i<Mesh->Face.Count;i++) | |
| Mesh->Face[i].Temp=-1; // not encoded yet | |
| for(i=0;i<Mesh->Vert.Count;i++) | |
| Mesh->Vert[i].Temp=0; // not encoded yet | |
| Coder.InitEncode(p+2); | |
| DV.Init(sDV_LOWRANGE); | |
| DVFlag.Init(2); | |
| VertPos = 0; | |
| while(1) | |
| { | |
| // initialization | |
| seed = 0; | |
| while(seed<Mesh->Face.Count && Mesh->Face[seed].Temp!=-1) | |
| seed++; | |
| if(seed == Mesh->Face.Count) | |
| { | |
| DV.Encode(Coder,0); // end of stream | |
| break; | |
| } | |
| k = Mesh->GetDegree(seed); | |
| if(k<sDV_LOWRANGE) | |
| DV.Encode(Coder,k-1); | |
| else | |
| { | |
| DV.Encode(Coder,sDV_LOWRANGE-1); | |
| Coder.EncodeGamma(k-sDV_LOWRANGE); | |
| } | |
| DVFlag.Encode(Coder,!Mesh->Face[seed].Material); | |
| f = AddFace(k); | |
| e = Mesh->Face[seed].Edge; | |
| Mesh->Face[seed].Temp = (sInt) f; | |
| f->Temp = e; | |
| for(i=0;i<k;i++) | |
| { | |
| ActivateVE(f,i,e); | |
| e = Mesh->NextFaceEdge(e); | |
| } | |
| // mainloop | |
| while(avPos) | |
| { | |
| // pick vert to complete | |
| j = 64; | |
| for(i=0;i<avPos;i++) | |
| { | |
| v = (MeshElement *) Mesh->Vert[avList[i]].Temp; | |
| sVERIFY(v != 0); | |
| k = 0; | |
| for(il=0;il<v->Degree;il++) | |
| { | |
| if(!v->Elem[il]) | |
| k++; | |
| } | |
| if(k<j) | |
| { | |
| vi = i; | |
| j = k; | |
| } | |
| } | |
| v = (MeshElement *) Mesh->Vert[avList[vi]].Temp; | |
| sVERIFY(v != 0); | |
| e = v->Temp; | |
| for(j=0;j<v->Degree;j++) | |
| { | |
| if(!v->Elem[j]) // empty slot | |
| { | |
| // activate face | |
| sVERIFY(Mesh->GetFace(e)->Temp == -1); | |
| d = Mesh->GetDegree(Mesh->GetFaceId(e)); | |
| if(d<sDV_LOWRANGE) | |
| DV.Encode(Coder,d-1); | |
| else | |
| { | |
| DV.Encode(Coder,sDV_LOWRANGE-1); | |
| Coder.EncodeGamma(d-sDV_LOWRANGE); | |
| } | |
| DVFlag.Encode(Coder,!Mesh->GetFace(e)->Material); | |
| f = AddFace(d); | |
| Mesh->GetFace(e)->Temp = (sInt) f; | |
| f->Temp = e; | |
| AddFaceToVertex(f,0,v,j); | |
| // complete face | |
| i = ForceFV(f,j,1); | |
| il = ForceFV(f,j,-1); | |
| if(i) | |
| { | |
| for(k=0,ee=e;k<i;k++) | |
| ee = Mesh->NextFaceEdge(ee); | |
| while(i<=il) | |
| { | |
| ActivateVE(f,i++,ee); | |
| ee = Mesh->NextFaceEdge(ee); | |
| } | |
| } | |
| for(i=0;i<f->Degree;i++) | |
| sVERIFY(f->Elem[i]!=0); | |
| } | |
| e = NextVertSlot(e); | |
| } | |
| sVERIFY(e == v->Temp); | |
| // remove vert from queue | |
| avList[vi] = avList[--avPos]; | |
| } | |
| } | |
| for(i=0;i<Mesh->Face.Count;i++) | |
| sVERIFY(Mesh->Face[i].Temp != 0); | |
| for(i=0;i<Mesh->Vert.Count;i++) | |
| sVERIFY(Mesh->Vert[i].Temp != 0); | |
| delete[] Face; | |
| delete[] Vert; | |
| *(sU16 *) p = Mesh->Vert.Count; p+=2; | |
| DV.Exit(); | |
| DVFlag.Exit(); | |
| Coder.FinishEncode(); | |
| p += Coder.GetBytes(); | |
| } | |
| sInt MeshCoder::NextVertSlot(sInt e) | |
| { | |
| sInt ec; | |
| ec = e; | |
| do | |
| { | |
| e = Mesh->NextVertEdge(e); | |
| } | |
| while(Mesh->GetVertId(e) != Mesh->GetVertId(ec)); | |
| return e; | |
| } | |
| sInt MeshCoder::FindFirstVert(sInt v) | |
| { | |
| MeshElement *e; | |
| sInt vt; | |
| if(Mesh->Vert[Mesh->Vert[v].First].Temp) // first already encoded? | |
| { | |
| e = (MeshElement *) Mesh->Vert[Mesh->Vert[v].First].Temp; | |
| return e - Vert; | |
| } | |
| else | |
| { | |
| // make this the first | |
| vt = v; | |
| do | |
| { | |
| Mesh->Vert[v].First = vt; | |
| v = Mesh->Vert[v].Next; | |
| } | |
| while(v!=vt); | |
| return -1; | |
| } | |
| } | |
| GenMesh *MeshCoder::MakeClosedMesh(GenMesh *msh) | |
| { | |
| sInt i,j,k,d; | |
| sInt Edges[64],fc,e,ee,fa; | |
| GenMesh *Mesh; | |
| Mesh = new GenMesh; | |
| Mesh->Init(msh->VertMask,msh->VertCount); | |
| // copy vertices | |
| Mesh->Vert.AtLeast(msh->Vert.Count); | |
| Mesh->Vert.Count=msh->Vert.Count; | |
| for(i=0;i<msh->Vert.Count;i++) | |
| { | |
| Mesh->Vert[i]=msh->Vert[i]; | |
| Mesh->Vert[i].First=i; | |
| } | |
| sCopyMem4((sU32 *)Mesh->VertBuf,(sU32 *)msh->VertBuf,4*msh->VertSize*msh->VertCount); | |
| // copy non-deleted faces and create edges | |
| for(i=0;i<msh->Face.Count;i++) | |
| { | |
| if(msh->Face[i].Material) | |
| { | |
| Mesh->Face.AtLeast(Mesh->Face.Count+1); | |
| fc = Mesh->Face.Count++; | |
| Mesh->Face[fc].Init(); | |
| Mesh->Face[fc].Material = msh->Face[i].Material; | |
| e = ee = msh->Face[i].Edge; | |
| j = 0; | |
| do | |
| { | |
| Edges[j++] = Mesh->AddEdge(msh->GetVertId(e),msh->GetVertId(msh->NextFaceEdge(e)),fc); | |
| sVERIFY(j<=64); | |
| e = msh->NextFaceEdge(e); | |
| } | |
| while(e!=ee); | |
| d=j; | |
| for(j=0;j<d;j++) | |
| { | |
| k=Edges[j]; | |
| Mesh->Edge[k/2].Next[k&1] = Edges[(j+1) %d]; | |
| Mesh->Edge[k/2].Prev[k&1] = Edges[(j-1+d)%d]; | |
| } | |
| } | |
| } | |
| // fix vertices | |
| for(i=0;i<msh->Vert.Count;i++) | |
| Mesh->Vert[i].First=msh->Vert[i].First; | |
| // close connected components | |
| fa = 0; | |
| for(i=0;i<Mesh->Edge.Count;i++) | |
| { | |
| if(Mesh->Edge[i].Face[1]==-1) // boundary found | |
| { | |
| e = i*2+1; | |
| Mesh->Face.AtLeast(Mesh->Face.Count+1); | |
| fc = Mesh->Face.Count++; | |
| Mesh->Face[fc].Init(); | |
| Mesh->Face[fc].Material = 0; | |
| Mesh->Face[fc].Edge = e; | |
| fa++; | |
| do | |
| { | |
| ee = e; | |
| do | |
| { | |
| e = Mesh->PrevVertEdge(e); | |
| } | |
| while(Mesh->GetFaceId(e^1)!=-1); | |
| e ^= 1; | |
| sVERIFY(Mesh->Edge[ee/2].Prev[ee&1] == -1); | |
| sVERIFY(Mesh->Edge[e/2].Next[e&1] == -1); | |
| Mesh->Edge[ee/2].Prev[ee&1] = e; | |
| Mesh->Edge[e/2].Next[e&1] = ee; | |
| } | |
| while(i*2+1!=e); | |
| ee=e; j=0; | |
| do | |
| { | |
| Mesh->Edge[e/2].Face[e&1] = fc; | |
| e = Mesh->NextFaceEdge(e); | |
| j++; | |
| } | |
| while(e!=ee); | |
| } | |
| } | |
| Mesh->Verify(); | |
| return Mesh; | |
| } | |
| void MeshCoder::ActivateVE(MeshElement *f,sInt i,sInt edg) | |
| { | |
| sInt j,k,val,vt,e,ee; | |
| MeshElement *v; | |
| vt = Mesh->GetVertId(edg); | |
| for(j=0;j<avPos;j++) | |
| { | |
| if(avList[j]==vt) | |
| break; | |
| } | |
| if(j==avPos) // add | |
| { | |
| val = Mesh->GetValence(edg); | |
| v = AddVert(val); | |
| VertOrder[VertPos++] = vt; | |
| if(val<sDV_LOWRANGE) | |
| DV.Encode(Coder,val-1); | |
| else | |
| { | |
| DV.Encode(Coder,sDV_LOWRANGE-1); | |
| Coder.EncodeGamma(val-sDV_LOWRANGE); | |
| } | |
| j = FindFirstVert(vt); | |
| DVFlag.Encode(Coder,j != -1); | |
| if(j!=-1) | |
| Coder.EncodeGamma(j); | |
| f->Elem[i] = v; | |
| v->Elem[0] = f; | |
| v->Temp = edg; | |
| avList[avPos++] = vt; | |
| sVERIFY(avPos<256); | |
| Mesh->Vert[vt].Temp = (sInt) v; | |
| } | |
| else // split | |
| { | |
| v = (MeshElement *) Mesh->Vert[vt].Temp; | |
| sVERIFY(v != 0); | |
| DV.Encode(Coder,0); | |
| Coder.EncodeGamma(j); | |
| j = 0; | |
| k = Mesh->GetFaceId(f->Temp); | |
| e = ee = v->Temp; | |
| while(Mesh->GetFaceId(e) != k) | |
| { | |
| j++; | |
| e = NextVertSlot(e); | |
| sVERIFY(e != ee); | |
| } | |
| Coder.EncodePlain(j,v->Degree); | |
| AddFaceToVertex(f,i,v,j); | |
| } | |
| } | |
| MeshElement *MeshCoder::AddFace(sInt deg) | |
| { | |
| Face[FaceCtr].Init(deg); | |
| return &Face[FaceCtr++]; | |
| } | |
| MeshElement *MeshCoder::AddVert(sInt deg) | |
| { | |
| Vert[VertCtr].Init(deg); | |
| return &Vert[VertCtr++]; | |
| } | |
| #endif | |
| sU8 *MeshCoder::Decode(GenMesh *msh,sU8 *p) | |
| { | |
| sInt i,j,k,d,vi,fc; | |
| MeshElement *f,*v; | |
| // parse header | |
| i = *(sU16 *) p; p+=2; | |
| Coder.InitDecode(p); | |
| DV.Init(sDV_LOWRANGE); | |
| DVFlag.Init(2); | |
| MeshElement::ResetStorage(); | |
| Face = new MeshElement[16384]; | |
| Vert = new MeshElement[i]; | |
| FaceCtr = 0; | |
| VertCtr = 0; | |
| avPos = 0; | |
| Mesh = msh; | |
| Mesh->Face.Count = 0; | |
| FaceCount = 0; | |
| while(1) | |
| { | |
| f = DecodeFace(); | |
| if(!f) | |
| break; | |
| for(i=0;i<f->Degree;i++) | |
| ActivateVD(f,i); | |
| do | |
| { | |
| j = 64; | |
| for(i=0;i<avPos;i++) | |
| { | |
| v = &Vert[avList[i]]; | |
| for(d=0,k=0;d<v->Degree;d++) | |
| { | |
| if(!v->Elem[d]) | |
| k++; | |
| } | |
| if(k<j) | |
| { | |
| j=k; | |
| vi=i; | |
| } | |
| } | |
| v = &Vert[avList[vi]]; | |
| sVERIFY(v != 0); | |
| for(j=0;j<v->Degree;j++) | |
| { | |
| if(!v->Elem[j]) | |
| { | |
| f = DecodeFace(); | |
| AddFaceToVertex(f,0,v,j); | |
| k = ForceFV(f,j,1); | |
| i = ForceFV(f,j,-1); | |
| if(k) | |
| { | |
| while(k<=i) | |
| ActivateVD(f,k++); | |
| } | |
| } | |
| } | |
| avList[vi] = avList[--avPos]; | |
| } | |
| while(avPos); | |
| } | |
| DV.Exit(); | |
| DVFlag.Exit(); | |
| p += Coder.GetBytes(); | |
| // the mesh topology should be complete now. | |
| // try and convert it into halfedges. | |
| Mesh->Face.AtLeast(FaceCount); | |
| Mesh->Face.Count=FaceCount; | |
| fc = 0; | |
| for(f=Face;f<Face+FaceCtr;f++) | |
| { | |
| sInt Edges[66],f0,f1; | |
| if(f->Temp) | |
| { | |
| Mesh->Face[fc].Init(); | |
| Mesh->Face[fc].Material=1; | |
| d = f->Degree; | |
| f0 = f->Elem[d-1]->Temp; | |
| for(j=0;j<d;j++) | |
| { | |
| f1 = f0; | |
| f0 = f->Elem[j]->Temp; | |
| Edges[j+1] = Mesh->AddEdge(f1,f0,fc); | |
| } | |
| Edges[0]=Edges[d]; | |
| Edges[d+1]=Edges[1]; | |
| for(j=0;j<d;j++) | |
| { | |
| k = Edges[j+1]; | |
| Mesh->Edge[k/2].Next[k&1] = Edges[j+2]; | |
| Mesh->Edge[k/2].Prev[k&1] = Edges[j]; | |
| } | |
| fc++; | |
| } | |
| } | |
| delete[] Face; | |
| delete[] Vert; | |
| return p; | |
| } | |
| MeshElement *MeshCoder::DecodeFace() | |
| { | |
| sInt d; | |
| sBool ok; | |
| MeshElement *f; | |
| d = DV.Decode(Coder); | |
| if(!d) | |
| return 0; | |
| if(++d == sDV_LOWRANGE) | |
| d += Coder.DecodeGamma(); | |
| ok = !DVFlag.Decode(Coder); | |
| FaceCount += ok; | |
| f = &Face[FaceCtr++]; | |
| f->Init(d); | |
| f->Temp = ok; | |
| return f; | |
| } | |
| void MeshCoder::ActivateVD(MeshElement *f,sInt i) | |
| { | |
| MeshElement *v; | |
| sInt val,j,vi; | |
| val = DV.Decode(Coder); | |
| if(val) // add | |
| { | |
| if(++val == sDV_LOWRANGE) | |
| val += Coder.DecodeGamma(); | |
| v = &Vert[VertCtr++]; | |
| v->Init(val); | |
| avList[avPos++] = vi = v->Temp = Mesh->AddNewVert(); | |
| if(DVFlag.Decode(Coder)) | |
| { | |
| j = Coder.DecodeGamma(); | |
| Mesh->Vert[vi].Next = Mesh->Vert[j].Next; | |
| Mesh->Vert[vi].First = Mesh->Vert[j].First; | |
| Mesh->Vert[j].Next = vi; | |
| } | |
| j=0; | |
| } | |
| else // split | |
| { | |
| v = &Vert[avList[Coder.DecodeGamma()]]; | |
| j = Coder.DecodePlain(v->Degree); | |
| } | |
| AddFaceToVertex(f,i,v,j); | |
| } | |
| sInt MeshCoder::ForceFV(MeshElement *f,sInt j,sInt dir) | |
| { | |
| MeshElement *v,*vt; | |
| sInt i; | |
| v = f->Elem[0]; | |
| i = 0; | |
| while(1) | |
| { | |
| i = (i+dir+f->Degree)%f->Degree; | |
| vt = v->Elem[(j-dir+v->Degree)%v->Degree]; | |
| v = f->Elem[i]; | |
| if(!i || !vt || !v) | |
| break; | |
| j = v->Find(vt,-dir); | |
| AddFaceToVertex(f,i,v,j); | |
| } | |
| return i; | |
| } | |
| void MeshCoder::AddFaceToVertex(MeshElement *f,sInt i,MeshElement *v,sInt j) | |
| { | |
| sInt dir,in; | |
| MeshElement *fp; | |
| f->Elem[i] = v; | |
| v->Elem[j] = f; | |
| for(dir=-1;dir<=1;dir+=2) | |
| { | |
| fp = v->Elem[(j+dir+v->Degree)%v->Degree]; | |
| in = (i-dir+f->Degree)%f->Degree; | |
| if(fp && !f->Elem[in]) | |
| f->Elem[in] = fp->Elem[fp->Find(v,dir)]; | |
| } | |
| } | |
| /****************************************************************************/ | |
| static sInt VertQuantize[3] = { 319,639,191 }; | |
| static sInt AnimQuantize[5] = { 15,31,63,127,255 }; | |
| static sF32 AnimThreshold[5] = { 0.0f,0.016f,0.03f,0.06f,0.10f }; | |
| void GenMesh::WriteCompact(sU8 *&p) | |
| { | |
| #if !sPLAYER | |
| sInt i,j,k,l; | |
| sVector *vp; | |
| sVector v; | |
| sF32 *vdim; | |
| // sInt imin,imax; | |
| sF32 fmin,fmax; | |
| MeshCoder *cod; | |
| sF32 *fp; | |
| sU8 *pstart; | |
| sInt vl[4],ev; | |
| fwrite srt[9]; | |
| RangeCoder coder; | |
| RangeModel vModel[5]; | |
| // check bounds | |
| sVERIFY(Vert.Count<0x7fff); | |
| sVERIFY(Face.Count<0x7fff); | |
| sVERIFY(KeyCount<0x7fff); | |
| sVERIFY(CurveCount<0xff); | |
| sVERIFY(BoneMatrix.Count<0xff); | |
| sVERIFY((VertMask & ~(sGMF_POS|sGMF_NORMALS|sGMF_COLOR0|sGMF_UV0))==0) | |
| // write header | |
| pstart = p; | |
| *p++ = KeyCount&0xff; | |
| *p++ = KeyCount>>8; | |
| *p++ = CurveCount; | |
| *p++ = BoneMatrix.Count; | |
| *p++ = VertMask&0xff; | |
| *p++ = VertMask>>8; | |
| sDPrintF("%04x %5d : header\n",p-pstart); pstart=p; | |
| // topology | |
| pstart = p; | |
| cod = new MeshCoder; | |
| cod->Encode(this,p); | |
| sDPrintF("%04x %5d : topology\n",p-pstart); pstart=p; | |
| sVERIFY(cod->VertPos == Vert.Count); | |
| // write vertices | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| k=cod->VertOrder[i]; | |
| for(j=0;j<4;j++) | |
| if(Vert[k].Matrix[j]==0xff) | |
| break; | |
| Vert[k].Temp = j; | |
| sVERIFY(j>=1 && j<=4); | |
| *p++ = j-1; | |
| } | |
| sDPrintF("%04x %5d : matrix count\n",p-pstart); pstart=p; | |
| vl[0]=vl[1]=vl[2]=vl[3]=0; | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| k=cod->VertOrder[i]; | |
| for(j=0;j<Vert[k].Temp;j++) | |
| { | |
| *p++ = Vert[k].Matrix[j]-vl[j]; | |
| vl[j] = Vert[k].Matrix[j]; | |
| } | |
| } | |
| sDPrintF("%04x %5d : matrix index\n",p-pstart); pstart=p; | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| k=cod->VertOrder[i]; | |
| for(j=0;j<Vert[k].Temp-1;j++) | |
| *p++ = Vert[k].Weight[j]; | |
| } | |
| sDPrintF("%04x %5d : matrix weight\n",p-pstart); pstart=p; | |
| // write vertex buffer | |
| vdim = (sF32 *) p; | |
| vdim[0] = vdim[3] = VertPos(0).x; | |
| vdim[1] = vdim[4] = VertPos(0).y; | |
| vdim[2] = vdim[5] = VertPos(0).z; | |
| for(i=1;i<Vert.Count;i++) | |
| { | |
| v = VertPos(i); | |
| vdim[0] = sMin(vdim[0],v.x); | |
| vdim[1] = sMin(vdim[1],v.y); | |
| vdim[2] = sMin(vdim[2],v.z); | |
| vdim[3] = sMax(vdim[3],v.x); | |
| vdim[4] = sMax(vdim[4],v.y); | |
| vdim[5] = sMax(vdim[5],v.z); | |
| } | |
| vdim[3] = (vdim[3] - vdim[0]) / VertQuantize[0]; | |
| vdim[4] = (vdim[4] - vdim[1]) / VertQuantize[1]; | |
| vdim[5] = (vdim[5] - vdim[2]) / VertQuantize[2]; | |
| p+=24; | |
| sDPrintF("%04x %5d : vert scaling\n",p-pstart); pstart=p; | |
| coder.InitEncode(p); | |
| for(i=0;i<3;i++) | |
| { | |
| vModel[i].Init(VertQuantize[i]+1); | |
| vl[i]=0; | |
| } | |
| vModel[3].Init(2); | |
| sF32 ex = vdim[3]/1.5f, ey = vdim[4]/1.5f, ez = vdim[5]/1.5f; | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| k = cod->VertOrder[i]; | |
| vp = VertBuf + k * VertSize; | |
| if(VertMask & sGMF_POS && cod->Mesh->Vert[k].First==k) | |
| { | |
| // search for mirror verts | |
| for(j=0;j<i;j++) | |
| { | |
| sVector *vp2 = VertBuf + cod->VertOrder[j] * VertSize; | |
| if(fabs(vp->x+vp2->x)<ex && fabs(vp->y-vp2->y)<ey && fabs(vp->z-vp2->z)<ez) | |
| break; | |
| } | |
| if(j==i) | |
| { | |
| vModel[3].Encode(coder,0); | |
| for(j=0;j<3;j++) | |
| { | |
| ev = sRange<sInt>(((&vp->x)[j]-vdim[j])/vdim[j+3]+0.5f,VertQuantize[j],0); | |
| vModel[j].Encode(coder,(ev-vl[j]+VertQuantize[j]+1) % (VertQuantize[j]+1)); | |
| vl[j] = ev; | |
| } | |
| } | |
| else | |
| { | |
| vModel[3].Encode(coder,1); | |
| coder.EncodePlain(j,i); | |
| } | |
| } | |
| if(VertMask & (sGMF_NORMAL | sGMF_TANGENT | sGMF_COLOR0 | sGMF_UV0)) | |
| sVERIFYFALSE; | |
| } | |
| coder.FinishEncode(); | |
| p += coder.GetBytes(); | |
| for(i=0;i<4;i++) | |
| vModel[i].Exit(); | |
| sDPrintF("%04x %5d : vertices\n",p-pstart); pstart=p; | |
| // keys | |
| for(i=0;i<BoneCurve.Count;i++) | |
| { | |
| BoneMatrix[BoneCurve[i].Matrix].TransSRT[BoneCurve[i].Curve] = BoneCurve[i].Curve < 3 ? 1 : 0; | |
| } | |
| for(i=0;i<BoneMatrix.Count;i++) | |
| { | |
| l = -(BoneMatrix[i].Parent+1-i); | |
| sVERIFY(l>=0 && l<255); | |
| *p++ = l; | |
| } | |
| sDPrintF("%04x %5d : bone matrix parent\n",p-pstart); pstart=p; | |
| for(j=0;j<9;j++) | |
| { | |
| srt[j].Init(BoneMatrix[0].BaseSRT[j]); | |
| for(i=0;i<BoneMatrix.Count;i++) | |
| { | |
| srt[j].Pre(BoneMatrix[i].BaseSRT[j]); | |
| srt[j].Pre(BoneMatrix[i].TransSRT[j]); | |
| } | |
| } | |
| for(j=0;j<9;j++) | |
| srt[j].Write0(p); | |
| for(j=0;j<9;j++) | |
| { | |
| for(i=0;i<BoneMatrix.Count;i++) | |
| srt[j].Write(p,BoneMatrix[i].BaseSRT[j]); | |
| for(i=0;i<BoneMatrix.Count;i++) | |
| srt[j].Write(p,BoneMatrix[i].TransSRT[j]); | |
| } | |
| sDPrintF("%04x %5d : bone matrix srt\n",p-pstart); pstart=p; | |
| for(i=0;i<BoneCurve.Count;i++) | |
| *p++ = BoneCurve[i].Curve; | |
| vl[0]=0; | |
| for(i=0;i<BoneCurve.Count;i++) | |
| { | |
| *p++ = BoneCurve[i].Matrix-vl[0]; | |
| vl[0] = BoneCurve[i].Matrix; | |
| } | |
| sDPrintF("%04x %5d : fcurve info\n",p-pstart); pstart=p; | |
| for(i=0;i<5;i++) | |
| vModel[i].Init(AnimQuantize[i]*2+2); | |
| coder.InitEncode(p+CurveCount*4); | |
| for(i=0;i<CurveCount;i++) | |
| { | |
| sInt sc,nsc; | |
| fp = &KeyBuf[i*KeyCount]; | |
| fmin = fp[0]; fmax = 0.0f; | |
| for(j=1;j<KeyCount;j++) | |
| fmax = sMax<sF32>(fmax,fabs(fp[j]-fmin)); | |
| fmin = fput(fmin,p); p+=2; | |
| fmax = fput(fmax,p); p+=2; | |
| for(j=0;j<5;j++) | |
| { | |
| if(fmax>=AnimThreshold[j]) | |
| { | |
| sc = AnimQuantize[j]; | |
| nsc = j; | |
| } | |
| } | |
| l=0; | |
| for(j=1;j<KeyCount;j++) | |
| { | |
| k = sRange<sInt>((fp[j] - fmin) / fmax * sc+0.5f,sc,-sc); | |
| ev = k-l; | |
| vModel[nsc].Encode(coder,ev & (sc*2+1)); | |
| l = k; | |
| } | |
| } | |
| coder.FinishEncode(); | |
| p += coder.GetBytes(); | |
| for(i=0;i<5;i++) | |
| vModel[i].Exit(); | |
| sDPrintF("%04x %5d : fcurve data\n",p-pstart); pstart=p; | |
| // end | |
| *p++ = 'r'; | |
| *p++ = 'y'; | |
| *p++ = 'g'; | |
| sDPrintF("%04x %5d : footer\n",p-pstart); pstart=p; | |
| delete cod; | |
| #endif | |
| } | |
| /****************************************************************************/ | |
| struct fread | |
| { | |
| sF32 min; | |
| sF32 max; | |
| void Read0(sU8 *&p); | |
| sF32 Read(sU8 *&p); | |
| }; | |
| void fread::Read0(sU8 *&p) | |
| { | |
| min = fget(p); p+=2; | |
| max = fget(p); p+=2; | |
| } | |
| sF32 fread::Read(sU8*&p) | |
| { | |
| return (*p++)*(max-min)/255+min; | |
| } | |
| void GenMesh::ReadCompact(sU8 *&pp,sU32 dgmf) | |
| { | |
| sInt i,j,k,vl[4],sc,nsc,bc; | |
| sU32 sgmf; | |
| sVector *vp,v0; | |
| #if !sINTRO_X | |
| sVector v; | |
| #endif | |
| // sInt imin,imax; | |
| sF32 fmin,fmax; | |
| sF32 *fp,*vdim; | |
| fread srt[9]; | |
| MeshCoder meshcode; | |
| RangeCoder coder; | |
| RangeModel vModel[5]; | |
| sU8 *p; | |
| p = pp; | |
| // read header | |
| KeyCount = *(sU16 *) p; | |
| CurveCount = p[2]; | |
| bc = p[3]; | |
| sgmf = *(sU16 *) (p+4); | |
| p+=6; | |
| #if sINTRO | |
| dgmf = 0x23; | |
| #endif | |
| Init(dgmf,64*1024); | |
| BoneMatrix.AtLeast(bc); BoneMatrix.Count = bc; | |
| BoneCurve.AtLeast(CurveCount); BoneCurve.Count = CurveCount; | |
| KeyBuf = new sF32[KeyCount*CurveCount]; | |
| // read topology | |
| p = meshcode.Decode(this,p); | |
| // read vertices | |
| for(i=0;i<Vert.Count;i++) | |
| Vert[i].Temp = 1 + *p++; | |
| for(i=0;i<4;i++) | |
| vl[i]=0; | |
| for(i=0;i<Vert.Count;i++) | |
| for(j=0;j<Vert[i].Temp;j++) | |
| { | |
| vl[j] = (vl[j] + *p++) & 0xff; | |
| Vert[i].Matrix[j] = vl[j]; | |
| } | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(Vert[i].Temp>0) | |
| { | |
| k = 0xff; | |
| for(j=0;j<Vert[i].Temp-1;j++) | |
| { | |
| k-= *p; | |
| Vert[i].Weight[j] = *p++; | |
| } | |
| Vert[i].Weight[Vert[i].Temp-1] = k; | |
| } | |
| } | |
| // read vertex buffer | |
| vdim = (sF32*) p; | |
| p += 24; | |
| vp = VertBuf; | |
| coder.InitDecode(p); | |
| for(i=0;i<3;i++) | |
| { | |
| vModel[i].Init(VertQuantize[i]+1); | |
| vl[i]=0; | |
| } | |
| vModel[3].Init(2); | |
| for(i=0;i<Vert.Count;i++) | |
| { | |
| if(sgmf & sGMF_POS) | |
| { | |
| if(Vert[i].First==i) | |
| { | |
| if(vModel[3].Decode(coder)) | |
| { | |
| k = coder.DecodePlain(i); | |
| v0 = VertBuf[k*VertSize]; | |
| v0.x = -v0.x; | |
| } | |
| else | |
| { | |
| for(j=0;j<3;j++) | |
| { | |
| vl[j] += vModel[j].Decode(coder); | |
| if(vl[j] > VertQuantize[j]) vl[j] -= VertQuantize[j]+1; | |
| (&v0.x)[j] = (vl[j] + sFGetRnd() - 0.5f) * vdim[j+3] + vdim[j]; | |
| } | |
| } | |
| v0.w = 1; | |
| } | |
| else | |
| v0 = VertBuf[Vert[i].First*VertSize]; | |
| } | |
| else | |
| v0.Init(0,0,0,1); | |
| if(dgmf & sGMF_POS && sCODECOVER(0)) | |
| *vp++ = v0; | |
| #if !sINTRO_X | |
| v.Init(0,0,0,0); | |
| if((dgmf & sGMF_NORMAL) && sCODECOVER(1)) | |
| *vp++ = v; | |
| if((dgmf & sGMF_TANGENT) && sCODECOVER(2)) | |
| *vp++ = v; | |
| v.Init(1,1,1,1); | |
| if((dgmf & sGMF_COLOR0) && sCODECOVER(4)) | |
| *vp++ = v; | |
| if((dgmf & sGMF_COLOR1) && sCODECOVER(5)) | |
| *vp++ = v; | |
| v.Init(v0.x*0.1f,v0.y*0.1f,0,0); | |
| if((dgmf & sGMF_UV0) && sCODECOVER(7)) | |
| *vp++ = v; | |
| if((dgmf & sGMF_UV1) && sCODECOVER(8)) | |
| *vp++ = v; | |
| if((dgmf & sGMF_UV2) && sCODECOVER(9)) | |
| *vp++ = v; | |
| if((dgmf & sGMF_UV3) && sCODECOVER(10)) | |
| *vp++ = v; | |
| #else | |
| /*if(dgmf & sGMF_NORMAL) | |
| vp++; | |
| if(dgmf & sGMF_TANGENT) | |
| vp++; | |
| if(dgmf & sGMF_UV0) | |
| { | |
| vp->Init(v0.x*0.1f,v0.y*0.1f,0,0); | |
| vp++; | |
| }*/ | |
| vp += 2; | |
| vp[-1].Init(v0.x*0.1f,v0.y*0.1f,0,0); | |
| #endif | |
| } | |
| p += coder.GetBytes(); | |
| for(i=0;i<4;i++) | |
| vModel[i].Exit(); | |
| // keys | |
| for(i=0;i<bc;i++) | |
| BoneMatrix[i].Parent = i - 1 - *p++; | |
| for(j=0;j<9;j++) | |
| srt[j].Read0(p); | |
| for(j=0;j<9;j++) | |
| { | |
| for(i=0;i<bc;i++) | |
| BoneMatrix[i].BaseSRT[j] = srt[j].Read(p); | |
| for(i=0;i<bc;i++) | |
| BoneMatrix[i].TransSRT[j] = srt[j].Read(p); | |
| } | |
| for(i=0;i<BoneCurve.Count;i++) | |
| { | |
| BoneCurve[i].Curve = *p++; | |
| } | |
| vl[0]=0; | |
| for(i=0;i<BoneCurve.Count;i++) | |
| { | |
| vl[0] = (vl[0] + *p++) & 0xff; | |
| BoneCurve[i].Matrix = vl[0]; | |
| } | |
| coder.InitDecode(p+CurveCount*4); | |
| for(i=0;i<5;i++) | |
| vModel[i].Init(AnimQuantize[i]*2+2); | |
| for(i=0;i<CurveCount;i++) | |
| { | |
| fmin = fget(p+0); | |
| fmax = fget(p+2); | |
| p += 4; | |
| for(j=0;j<5;j++) | |
| { | |
| if(fmax>=AnimThreshold[j]) | |
| { | |
| sc = AnimQuantize[j]; | |
| nsc = j; | |
| } | |
| } | |
| fp = &KeyBuf[i*KeyCount]; | |
| *fp++ = fmin; | |
| k = 0; | |
| for(j=1;j<KeyCount;j++) | |
| { | |
| k += vModel[nsc].Decode(coder); | |
| if(k & (sc+1)) | |
| k |= ~sc; | |
| else | |
| k &= sc; | |
| *fp++ = k * fmax / sc + fmin; | |
| } | |
| } | |
| p += coder.GetBytes(); | |
| for(i=0;i<5;i++) | |
| vModel[i].Exit(); | |
| // end | |
| #if !sPLAYER | |
| Verify(); | |
| #endif | |
| sVERIFY(p[0] == 'r'); | |
| sVERIFY(p[1] == 'y'); | |
| sVERIFY(p[2] == 'g'); | |
| p+=3; | |
| pp = p; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Cube(GenMesh *mesh,sInt tx,sInt ty,sInt tz,sInt crease) | |
| { | |
| sInt tess[3],i,j; | |
| sInt bm; | |
| sMatrix mat; | |
| sVector vc,vs; | |
| for(i=0;i<3;i++) | |
| tess[i]=(&tx)[i]>>16; | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mesh->Vert.Count==0); | |
| 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); | |
| // 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,1,0,0); | |
| mat.Init(); | |
| (&mat.l.x)[j] = 1.0f; | |
| mesh->RecBegin(); | |
| for(i=1;i<tess[j];i++) | |
| { | |
| mesh->Extrude(0x00010000,0x00000100); | |
| mesh->Face2Vert(); | |
| mesh->TransVert(mat); | |
| mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); | |
| } | |
| mesh->RecEnd(); | |
| } | |
| // rescale t0 0.5 .. -0.5 | |
| mat.Init(); | |
| mat.i.x = 1.0f/tess[0]; | |
| mat.j.y = 1.0f/tess[1]; | |
| mat.k.z = 1.0f/tess[2]; | |
| mesh->All2Sel(); | |
| mesh->TransVert(mat,sGMI_UV0,sGMI_UV0); | |
| mat.l.Init(-0.5f,-0.5f,-0.5f,1); | |
| mesh->TransVert(mat); | |
| // mapping | |
| if(crease) | |
| { | |
| 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,1,0,0); | |
| mesh->Crease(); | |
| mesh->Face2Vert(); | |
| sSetMem4((sU32 *)&mat,0,16); | |
| mat.l.x = 0.5f; | |
| mat.l.y = 0.5f; | |
| if(j/2==0) | |
| { | |
| mat.j.y = -1.0f; | |
| mat.k.x = 1.0f*bm; | |
| } | |
| else if(j/2==1) | |
| { | |
| mat.i.x = 1.0f; | |
| mat.k.y = -1.0f*bm; | |
| } | |
| else | |
| { | |
| mat.i.x = -1.0f*bm; | |
| mat.j.y = -1.0f; | |
| } | |
| mesh->TransVert(mat,sGMI_POS,sGMI_UV0); | |
| } | |
| } | |
| else | |
| { | |
| mesh->All2Mask(0,0); | |
| mat.Init(); | |
| mesh->TransVert(mat,sGMI_POS,sGMI_UV0); | |
| } | |
| mesh->All2Mask(0,~0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_SelectAll(GenMesh *mesh,sU32 dmask1,sU32 dmask0) | |
| { | |
| mesh->All2Mask(dmask1,dmask0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_SelectCube(GenMesh *mesh,sF323 center,sF323 size,sInt flags,sU32 dmask1,sU32 dmask0) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| mesh->SelectCube((sVector&)center.x,(sVector&)size.x,flags>>16,dmask1,dmask0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Subdivide(GenMesh *mesh,sInt mask,sF32 alpha,sInt count) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| count >>= 16; | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| while(count--) | |
| mesh->Subdivide(alpha); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Extrude(GenMesh *mesh,sInt smask,sInt mode,sInt dmask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| if(smask) | |
| mesh->Mask2Sel(smask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->Extrude(0,smask<<8,mode>>16); | |
| mesh->Face2Vert(); | |
| mesh->Sel2Mask(dmask<<16,0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Transform(GenMesh *mesh,sInt mask,sF323 s,sF323 r,sF323 t) | |
| { | |
| sMatrix mat; | |
| SCRIPTVERIFY(mesh); | |
| mesh->MarkAnimLabel(GMA_TRANSFORM); | |
| mat.InitSRT(&s.x); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<16); | |
| else | |
| mesh->All2Sel(); | |
| mesh->TransVert(mat); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Cylinder(GenMesh *mesh,sInt tx,sInt ty) | |
| { | |
| sInt i,sj,e; | |
| sMatrix mat,matuv; | |
| sVector vc,vs; | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mesh->Vert.Count==0); | |
| tx >>= 16; | |
| ty >>= 16; | |
| // create cylinder | |
| mesh->Ring(tx,0,0.5f,0); | |
| mat.Init(); | |
| mat.l.z = 1; | |
| matuv.Init(); | |
| matuv.l.y = 1.0f/ty; | |
| mesh->Face[0].Select = sTRUE; | |
| for(i=0;i<ty;i++) | |
| { | |
| e=mesh->Edge.Count; | |
| mesh->Extrude(0); | |
| mesh->Edge[e].Sel(0x000001); | |
| mesh->Face2Vert(); | |
| mesh->TransVert(mat); | |
| mesh->TransVert(matuv,sGMI_POS,sGMI_UV0); | |
| } | |
| // adjust size | |
| mat.Init(); | |
| mat.k.z = 1.0f/ty; | |
| mat.l.Init(0,0,-0.5f,1); | |
| mesh->All2Mask(0x00010000); | |
| mesh->Mask2Sel(0x00010000); | |
| mesh->TransVert(mat); | |
| // correct mapping | |
| sj = mesh->VertMap[sGMI_UV0]; | |
| if(sj!=-1) | |
| { | |
| for(i=-1;i<2;i+=2) | |
| { | |
| vs.Init(2,2,0.01f,1); | |
| vc.Init(0,0,i*0.5f,1); | |
| mesh->All2Mask(0,0x010100); | |
| mesh->Mask2Sel(0x010100); | |
| mesh->SelectCube(vc,vs,1,0,0); | |
| mesh->Crease(); | |
| mesh->Face2Vert(); | |
| matuv.Init(); | |
| matuv.j.y = i; | |
| matuv.l.Init(0.5f,0.5f,0,1); | |
| mesh->TransVert(matuv,sGMI_POS,sGMI_UV0); | |
| } | |
| mesh->All2Mask(0,0x010000); | |
| mesh->Mask2Sel(0x010001); | |
| 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); | |
| } | |
| mesh->All2Mask(0,~0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_NewMesh(sInt colorSets,sInt uvSets) | |
| { | |
| GenMesh *mesh; | |
| mesh = new GenMesh; | |
| mesh->Init(GenMesh::Features2Mask(0,1),1024); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Material(GenMesh *mesh,GenMaterial *mat,sInt id,sInt mask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mat); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->SetMaterial(id>>16,mat); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_TransformEx(GenMesh *mesh,sInt mask,sInt sj,sInt dj,sF323 s,sF323 r,sF323 t) | |
| { | |
| sMatrix mat; | |
| mesh->MarkAnimLabel(GMA_TRANSFORM); | |
| SCRIPTVERIFY(mesh); | |
| mat.InitSRT(&s.x); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<16); | |
| else | |
| mesh->All2Sel(); | |
| mesh->TransVert(mat,sj>>16,dj>>16); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Crease(GenMesh *mesh,sInt mask,sInt what,sInt selType) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| what >>= 16; | |
| SCRIPTVERIFY(what); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<(selType ? 0 : 8)); | |
| else | |
| mesh->All2Sel(); | |
| mesh->Crease(selType>>16,0,0,what); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_UnCrease(GenMesh *mesh,sInt mask,sInt what,sInt selType) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| what >>= 16; | |
| SCRIPTVERIFY(what); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->UnCrease(selType>>16,what); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_CalcNormals(GenMesh *mesh,sInt mode,sInt mask,sInt calcWhat) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->CalcNormals(mode>>16,1/*calcWhat>>16*/); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Torus(GenMesh *mesh,sInt tx,sInt ty,sF32 ri,sInt phase,sF32 arclen) | |
| { | |
| sInt i,n,e,f,t; | |
| sInt sj; | |
| sBool closed; | |
| sMatrix mat,matuv; | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mesh->Vert.Count==0); | |
| ri *= 0.5f; | |
| phase &= 0xffff; | |
| tx >>= 16; | |
| ty >>= 16; | |
| closed = arclen == 1.0f; | |
| // create torus | |
| mesh->Ring(ty,0,0.5f-ri,phase*sPI2/65536.0f); | |
| mat.Init(); | |
| mat.l.x = -0.5f-ri; | |
| 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;i<tx-closed;i++) | |
| { | |
| e = mesh->Edge.Count; | |
| mesh->Extrude(0); | |
| mesh->Edge[e].Sel(0x000001); | |
| 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;i<ty;i++) | |
| { | |
| mesh->Edge[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); | |
| // make the faces (and mark the v crease while we're at it) | |
| for(i=0;i<ty;i++) | |
| { | |
| n = (i+1)%ty; | |
| t = mesh->NextFaceEdge(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); | |
| } | |
| } | |
| // prepare the creases | |
| sj = mesh->VertMap[sGMI_UV0]; | |
| if(sj!=-1) | |
| { | |
| if(!closed) | |
| { | |
| mesh->All2Mask(0,0x000100); | |
| mesh->Mask2Sel(0x000100); | |
| 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(0,0x010000); | |
| 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); | |
| } | |
| } | |
| mesh->All2Mask(0,~0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Sphere(GenMesh *mesh,sInt tx,sInt ty) | |
| { | |
| sInt i,j,v,sj; | |
| sMatrix mat,matuv; | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mesh->Vert.Count==0); | |
| tx >>= 16; | |
| ty >>= 16; | |
| // first, generate a cheesy cylinder | |
| matuv.Init(); | |
| matuv.l.y = 1.0f / ty; | |
| mesh->Ring(tx,0,1.0f,0.0f); | |
| mesh->Face[mesh->Face.Count-1].Select = sTRUE; | |
| for(i=0;i<ty;i++) | |
| { | |
| mesh->Extrude(0); | |
| mesh->Face2Vert(); | |
| 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->All2Mask(0x010000); | |
| mesh->Mask2Sel(0x010000); | |
| mesh->TransVert(mat); | |
| // make it a sphere | |
| v=mesh->Vert.Count-tx*(ty+1); | |
| for(i=0;i<=ty;i++) | |
| { | |
| mesh->All2Mask(0,0x010000); | |
| mesh->Mask2Sel(0x010000); | |
| for(j=0;j<tx;j++,v++) | |
| mesh->Vert[v].Select=1; | |
| mat.Init(); | |
| mat.i.x = mat.k.z = sFSin((i+0.5f)*sPI/(ty+1)); | |
| mat.l.y = -sFCos((i+0.5f)*sPI/(ty+1)); | |
| mesh->TransVert(mat); | |
| } | |
| // fix top/bottom | |
| for(i=0;i<2;i++) | |
| { | |
| mesh->All2Mask(0,0x000100); | |
| mesh->Mask2Sel(0x000100); | |
| mesh->Face[i].Select=1; | |
| mesh->Triangulate(4); | |
| } | |
| // make the u-crease | |
| sj=mesh->VertMap[sGMI_UV0]; | |
| if(sj!=-1) | |
| { | |
| mesh->All2Mask(0,0x010000); | |
| mesh->Mask2Sel(0x010000); | |
| 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;i<mesh->Edge.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); | |
| } | |
| mesh->All2Mask(0,~0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Triangulate(GenMesh *mesh,sInt thres,sInt mask,sInt type) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| mesh->Triangulate(thres>>16,0,0,type>>16); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Cut(GenMesh *mesh,sF322 dir,sF32 offs,sInt mode) | |
| { | |
| sMatrix mat; | |
| sVector plane; | |
| SCRIPTVERIFY(mesh); | |
| mat.InitEulerPI2(&dir.x); | |
| plane.Init4(mat.i.x,mat.j.x,mat.k.x,offs); | |
| mesh->All2Sel(); | |
| mesh->Cut(plane,mode>>16); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_ExtrudeNormal(GenMesh *mesh,sF32 distance,sInt mask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<16); | |
| mesh->MarkAnimLabel(GMA_TRANSFORM); | |
| mesh->ExtrudeNormal(distance); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| #if !sINTRO_X | |
| sObject * __stdcall Mesh_Displace(GenMesh *mesh,GenBitmap *bmp,sF32 ampli,sInt mask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(bmp); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<16); | |
| mesh->Displace(bmp,ampli); | |
| return mesh; | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| #if !sINTRO_X | |
| sObject * __stdcall Mesh_Bevel(GenMesh *mesh,sF32 elev,sF32 pull,sInt mask,sInt mode,sInt dmask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| mesh->MarkAnimLabel(GMA_TRANSFORM); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->Bevel(elev,pull,mode>>16,0,mask<<8); | |
| mesh->Sel2Mask(dmask<<16,0); | |
| return mesh; | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Perlin(GenMesh *mesh,sInt mask,sF323 s,sF323 r,sF323 t,sF323 ampl) | |
| { | |
| sMatrix mat; | |
| SCRIPTVERIFY(mesh); | |
| mat.InitSRT(&s.x); | |
| mesh->MarkAnimLabel(GMA_PERLIN); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<16); | |
| mesh->Perlin(mat,(sVector&) ampl.x); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Add(GenMesh *mesh,GenMesh *mesh2) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| SCRIPTVERIFY(mesh2); | |
| if(mesh->Add(mesh2)) | |
| return mesh; | |
| else | |
| return 0; | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_DeleteFaces(GenMesh *mesh,sInt mask) | |
| { | |
| SCRIPTVERIFY(mesh); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mesh->DeleteFaces(); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| #if sINTRO | |
| extern "C" sU8 BabeMesh[]; | |
| #endif | |
| sObject * __stdcall Mesh_Babe(sChar *filename,sInt dummy,sInt anim0,sInt anim1,sInt phase,sInt flags) | |
| { | |
| GenMesh *mesh; | |
| sU8 *data,*origData; | |
| SCRIPTVERIFY(filename); | |
| #if !sINTRO | |
| data = sSystem->LoadFile(filename); | |
| #else | |
| data = BabeMesh; | |
| #endif | |
| SCRIPTVERIFY(data); | |
| if(data) | |
| { | |
| mesh = new GenMesh; | |
| origData = data; | |
| mesh->ReadCompact(data,GenMesh::Features2Mask(0,1)); | |
| if(!(flags & 0x10000)) | |
| mesh->RecStoreMode(); | |
| mesh->MarkAnimLabel(GMA_BONE); | |
| mesh->Anim0 = anim0>>16; | |
| mesh->Anim1 = anim1>>16; | |
| mesh->Bones((phase&0xffff)/65536.0f); | |
| mesh->All2Mask(0,~0); | |
| #if !sINTRO | |
| delete[] origData; | |
| #endif | |
| return mesh; | |
| } | |
| else | |
| return 0; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_BeginRecord(GenMesh *mesh) | |
| { | |
| SCRIPTVERIFY(mesh->RecMode==0); | |
| mesh->RecStoreMode(); | |
| return mesh; | |
| } | |
| sObject * __stdcall Mesh_AnimLabel(GenMesh *mesh,sInt label,sU32 flags) | |
| { | |
| mesh->SetAnimLabel(label,flags>>16); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_SelectRandom(GenMesh *mesh,sU32 ratio,sInt seed,sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i; | |
| volatile sInt dummy; | |
| seed>>=16; | |
| ratio>>=16; | |
| sSetRndSeed(seed+seed*31743^(seed<<23)); | |
| #if sINTRO_X | |
| i = mesh->Vert.Count; | |
| if(dmask0&0x80) | |
| i *= 2; | |
| i += mesh->Edge.Count; | |
| while(i>0) | |
| { | |
| dummy=sGetRnd(); | |
| i--; | |
| } | |
| for(i=0;i<mesh->Face.Count;i++) | |
| mesh->Face[i].Select=(sGetRnd()>>24)<=ratio && mesh->Face[i].Material; | |
| #else | |
| for(i=0;i<mesh->Edge.Count;i++) | |
| mesh->Edge[i].Select=(sGetRnd()>>24)<=ratio; | |
| if(dmask0&0x80) | |
| for(i=0;i<mesh->Vert.Count;i++) | |
| dummy=sGetRnd(); | |
| for(i=0;i<mesh->Vert.Count;i++) | |
| mesh->Vert[i].Select=(sGetRnd()>>24)<=ratio; | |
| for(i=0;i<mesh->Vert.Count;i++) | |
| mesh->Vert[i].Select=mesh->Vert[mesh->Vert[i].First].Select; | |
| for(i=0;i<mesh->Face.Count;i++) | |
| mesh->Face[i].Select=(sGetRnd()>>24)<=ratio && mesh->Face[i].Material; | |
| dmask0 &= ~0x80; | |
| #endif | |
| mesh->Sel2Mask(dmask1,dmask0); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_Multiply(GenMesh *mesh,sF323 s,sF323 r,sF323 t,sInt count) | |
| { | |
| sInt i; | |
| GenMesh *out; | |
| sMatrix xform,step; | |
| count>>=16; | |
| step.InitSRT(&s.x); | |
| out = new GenMesh; | |
| out->Init(mesh->VertMask,mesh->VertCount*count); | |
| xform = step; | |
| while(count--) | |
| { | |
| out->Add(mesh); | |
| for(i=0;i<out->Vert.Count-mesh->Vert.Count;i++) | |
| out->Vert[i].Select=0; | |
| while(i<out->Vert.Count) | |
| out->Vert[i++].Select=1; | |
| out->TransVert(xform); | |
| xform.Mul4(step); | |
| } | |
| return out; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_SelectAngle(GenMesh *mesh,sF32 angle,sU32 dmask1,sU32 dmask0) | |
| { | |
| sInt i; | |
| sVector f0,f1; | |
| angle = cos(angle*sPI2F*0.25f); | |
| for(i=0;i<mesh->Edge.Count;i++) | |
| { | |
| mesh->CalcFaceNormal(f0,mesh->GetFaceId(i*2 )); f0.UnitSafe3(); | |
| mesh->CalcFaceNormal(f1,mesh->GetFaceId(i*2+1)); f1.UnitSafe3(); | |
| if(sFAbs(f0.Dot3(f1))<angle) | |
| mesh->Edge[i].Sel(dmask1,dmask0); | |
| } | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| sObject * __stdcall Mesh_ExtrudeWK(GenMesh *mesh,sInt mask,sInt mode,sInt count,sF32 distance,sF323 s,sF323 r,sInt scalemode) | |
| { | |
| sInt i,j,grp,e,ee,mi; | |
| sU32 *data; | |
| sBool local; | |
| static sInt stk[4096]; | |
| sMatrix mat; | |
| mesh->MarkAnimLabel(GMA_EWK); | |
| if(mask) | |
| mesh->Mask2Sel(mask<<8); | |
| else | |
| mesh->All2Sel(); | |
| mode >>= 16; | |
| count >>= 16; | |
| local = !(scalemode >> 16); | |
| // first, classify faces | |
| for(i=0;i<mesh->Face.Count;i++) | |
| mesh->Face[i].Temp = local ? -1 : 0; | |
| grp = local ? 0 : 1; | |
| while(1) | |
| { | |
| for(i=0;i<mesh->Face.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)) | |
| { | |
| mesh->Face[i].Temp = -2; | |
| stk[j++] = i; | |
| } | |
| e = mesh->NextFaceEdge(e); | |
| } | |
| while(e!=ee); | |
| } | |
| grp++; | |
| } | |
| mesh->RecBegin(); | |
| mat.i.Init(s.x,s.y,s.z,distance); | |
| mat.j.Init(r.x,r.y,r.z,count); | |
| mi = mesh->RecMatrix(mat); | |
| // main extrusion loop | |
| while(count--) | |
| { | |
| mesh->Extrude(0,0,mode); | |
| data = mesh->RecBegin(IM_EWK); | |
| mesh->RecOpCount = grp; | |
| // write parameters | |
| *data++ = local; | |
| *data++ = mi; | |
| // write groups | |
| for(i=0;i<mesh->Vert.Count;i++) | |
| mesh->Vert[i].Temp=0; | |
| for(i=0;i<grp;i++) | |
| { | |
| j = 0; | |
| for(e=0;e<mesh->Edge.Count*2;e++) | |
| { | |
| if(mesh->GetFace(e)->Select && mesh->GetFace(e)->Temp==i && !mesh->GetVert(e)->Temp) | |
| { | |
| mesh->GetVert(e)->Temp = 1; | |
| data[++j] = mesh->GetVertId(e); | |
| } | |
| } | |
| data[0] = j; | |
| data += j+1; | |
| } | |
| mesh->RecEnd(data); | |
| } | |
| mesh->RecEnd(); | |
| return mesh; | |
| } | |
| /****************************************************************************/ | |
| /****************************************************************************/ | |
| #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;i<xsi->Models->GetCount();i++) | |
| { | |
| xm = xsi->Models->Get(i); | |
| sDPrintF("mesh %08x\n",xm); | |
| first = Vert.Count; | |
| for(j=0;j<xm->Clusters->GetCount();j++) | |
| { | |
| xc = xm->Clusters->Get(j); | |
| ImportXSI(xc,first); | |
| } | |
| Verify(); | |
| for(j=0;j<xm->FCurves->GetCount();j++) | |
| { | |
| xf = xm->FCurves->Get(j); | |
| fi = xf->Index; | |
| sVERIFY(fi>=0 && fi<CurveCount); | |
| BoneCurve[fi].Curve = xf->Offset; | |
| BoneCurve[fi].Matrix = xm->Index; | |
| for(k=0;k<xf->KeyCount;k++) | |
| { | |
| sVERIFY(xf->Keys[k].Num>=0 && xf->Keys[k].Num<KeyCount); | |
| KeyBuf[KeyCount*fi+xf->Keys[k].Num] = xf->Keys[k].Pos; | |
| } | |
| } | |
| } | |
| sDPrintF("Bones: %d, Curves:%d, Keys:%d,Bytes %d\n",BoneMatrix.Count,CurveCount,KeyCount,KeyCount*CurveCount); | |
| } | |
| 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;i<fcc;i++) | |
| { | |
| xfc = xm->FCurves->Get(i); | |
| KeyCount = sMax(KeyCount,xfc->Keys[xfc->KeyCount-1].Num+1); | |
| xfc->Index = cc+i; | |
| } | |
| CurveCount+=fcc; | |
| } | |
| for(i=0;i<xm->Childs->GetCount();i++) | |
| ImportXSIR(xm->Childs->Get(i),cm); | |
| } | |
| 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]; | |
| sDPrintF("cluster %08x\n",xc); | |
| vc = Vert.Count; | |
| Vert.AtLeast(vc+xc->VertexCount); | |
| Realloc(vc+xc->VertexCount); | |
| // add vertices | |
| for(i=0;i<xc->VertexCount;i++) | |
| { | |
| v = xc->Vertices[i].Pos; | |
| for(j=first;j<Vert.Count;j++) | |
| { | |
| if(v.x==VertPos(j).x && v.y==VertPos(j).y && v.z==VertPos(j).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->w = 1; | |
| vp++; | |
| Vert[vj].Init(); | |
| for(j=0;j<4;j++) | |
| { | |
| if(j<xc->Vertices[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_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(fp<xc->Faces+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;i<max;i++) | |
| { | |
| sVERIFY(i==0 || fp[i*2]==0); | |
| vj = vi; | |
| vi = fp[max*2-1-2*i]; | |
| edges[i] = AddEdge(xc->Vertices[vj].Temp,xc->Vertices[vi].Temp,fi); | |
| } | |
| fp += max*2; | |
| for(i=0;i<max;i++) | |
| { | |
| j = edges[i]; | |
| Edge[j/2].Next[j&1] = edges[(i+1 )%max]; | |
| Edge[j/2].Prev[j&1] = edges[(i-1+max)%max]; | |
| } | |
| } | |
| } | |
| #endif | |
| /****************************************************************************/ | |
| /****************************************************************************/ |