////////////////////////////////////////////////////////////////////// // // Utils // // File: utils.cpp // Description : Various utility functions // // History: // -:Created by Anton Knyazev // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "utils.h" #include "primitives.h" #if defined(WIN64) __declspec(noinline) int float2int(float x) { //return x>0 ? (int)(x+0.5f) : (int)(x-0.5f); floatint u; u.fval = x+fmag; return u.ival-imag; } #endif #if defined(LINUX64) int float2int(float x) { //return x>0 ? (int)(x+0.5f) : (int)(x-0.5f); floatint u; u.fval = x+fmag; return u.ival-imag; } #endif // Mass properties calculations void compute_projection_integrals(vectorr *ab, real pi[10]) { real a0[4],b0[4],a1[3],b1[3],C[4][3],da,db; int i,edge; for(i=0;i<10;i++) pi[i]=0; for(edge=0;edge<3;edge++,ab++) { for(i=1,a0[0]=ab[0].x;i<4;i++) a0[i]=a0[i-1]*ab[0].x; for(i=1,b0[0]=ab[0].y;i<4;i++) b0[i]=b0[i-1]*ab[0].y; for(i=1,a1[0]=ab[1].x;i<3;i++) a1[i]=a1[i-1]*ab[1].x; for(i=1,b1[0]=ab[1].y;i<3;i++) b1[i]=b1[i-1]*ab[1].y; for(i=1,C[0][0]=a1[1]+a1[0]*a0[0]+a0[1]; i<3; i++) C[0][i]=a1[0]*C[0][i-1]+a0[i+1]; for(i=1,C[1][0]=b1[1]+b1[0]*b0[0]+b0[1]; i<3; i++) C[1][i]=b1[0]*C[1][i-1]+b0[i+1]; da=a1[0]-a0[0]; db=b1[0]-b0[0]; C[2][0] = 3*a1[1]+2*a1[0]*a0[0]+a0[1]; C[2][1] = a0[0]*C[2][0]+4*a1[2]; C[2][2] = 4*b1[2]+3*b1[1]*b0[0]+2*b1[0]*b0[1]+b0[2]; C[3][0] = 3*a0[1]+2*a0[0]*a1[0]+a1[1]; C[3][1] = a1[0]*C[3][0]+4*a0[2]; C[3][2] = 4*b0[2]+3*b0[1]*b1[0]+2*b0[0]*b1[1]+b1[2]; pi[0] += db*(a0[0]+a1[0]); for(i=0;i<3;i++) { pi[i+1] += db*C[0][i]; pi[i+4] += da*C[1][i]; } pi[7] += db*(b1[0]*C[2][0]+b0[0]*C[3][0]); pi[8] += db*(b1[0]*C[2][1]+b0[0]*C[3][1]); pi[9] += da*(a1[0]*C[2][2]+a0[0]*C[3][2]); } pi[0]*=0.5; pi[1]*=1.0/6; pi[2]*=1.0/12; pi[3]*=1.0/20; pi[4]*=-1.0/6; pi[5]*=-1.0/12; pi[6]*=-1.0/20; pi[7]*=1.0/24; pi[8]*=1.0/60; pi[9]*=-1.0/60; } void compute_face_integrals(vectorr *p,vectorr n, real fi[12]) { real pi[10],k[4],t,w; int i; compute_projection_integrals(p, pi); w = -(n*p[0]); for(k[0]=1.0/n.z,i=1;i<4;i++) k[i]=k[i-1]*k[0]; for(i=0;i<3;i++) fi[i*3+0] = k[0]*pi[i+1]; // a, a2, a3 for(i=0;i<3;i++) fi[i*3+1] = k[0]*pi[i+4]; // b, b2, b3 // a2b, b2g, g2a fi[9] = k[0]*pi[8]; fi[10] = -k[1]*(n.x*pi[9] + n.y*pi[6] + w*pi[5]); fi[11] = k[2]*(n.x*n.x*pi[3] + n.y*n.y*pi[9] + w*w*pi[1] + 2*(n.x*n.y*pi[8] + n.x*w*pi[2] + n.y*w*pi[7])); for(i=0,t=n.x; i<3; i++,t*=n.x) pi[i+1]*=t; for(i=0,t=n.y; i<3; i++,t*=n.y) pi[i+4]*=t; for(i=0;i<3;i++) pi[i+7] *= n.x*n.y; pi[8]*=n.x; pi[9]*=n.y; // g, g2, g3 fi[2] = -k[1]*(pi[1] + pi[4] + w*pi[0]); fi[5] = k[2]*(pi[2] + 2*pi[7] + pi[5] + w*(2*(pi[1] + pi[4]) + w*pi[0])); fi[8] = -k[3]*(pi[3] + 3*(pi[8] + pi[9]) + pi[6] + w*(3*(pi[2] + pi[5] + 2*pi[7] + w*(pi[1] + pi[4])) + w*w*pi[0])); } real ComputeMassProperties(strided_pointer points, const index_t *faces, int nfaces, vectorr ¢er,matrix3x3 &I) { real M=0,fi[12],nmax,diag[3]={0,0,0}; vectorr n,p[4]; int i,g; center.zero(); I.SetZero(); for(nfaces--; nfaces>=0; nfaces--,faces+=3) { n = points[faces[1]]-points[faces[0]] ^ points[faces[2]]-points[faces[0]]; if (n.len2()<1E-8) continue; n.normalize(); for(i=0,nmax=-1;i<3;i++) if (n[i]*n[i]>nmax) { nmax = n[i]*n[i]; g=i; } for(i=0;i<3;i++) p[i] = points[faces[i]].permutated(g); p[3]=p[0]; n = n.permutated(g); compute_face_integrals(p,n, fi); g = g^g>>1^1; for(i=0;i<4;i++) ((vectorr*)fi)[i] = ((vectorr*)fi)[i].permutated(g); n = n.permutated(g); M += n.x*fi[0]; for(i=0;i<3;i++) { center[i] += n[i]*fi[i+3]; diag[i] += n[i]*fi[i+6]; } I(0,1) += n.x*fi[9]; I(1,2) += n.y*fi[10]; I(0,2) += n.z*fi[11]; } if (M>0) center /= M*2; I(0,0) = (diag[1]+diag[2])*(1.0/3) - M*(center.y*center.y + center.z*center.z); I(1,1) = (diag[0]+diag[2])*(1.0/3) - M*(center.x*center.x + center.z*center.z); I(2,2) = (diag[0]+diag[1])*(1.0/3) - M*(center.x*center.x + center.y*center.y); I(1,0) = I(0,1) = -I(0,1)*0.5+M*center.x*center.y; I(2,0) = I(0,2) = -I(0,2)*0.5+M*center.x*center.z; I(2,1) = I(1,2) = -I(1,2)*0.5+M*center.y*center.z; return M; } void ComputeMeshEigenBasis(strided_pointer pVertices,const index_t *pIndices,int nTris, vectorr *eigen_axes,vectorr ¢er) { int i,j,k; vectorr m,mean(zero),v[3]; real s,t,sum=0, mtxbuf[9]; matrix C(3,3, mtx_symmetric, mtxbuf); C.zero(); // find mean point for(i=0; i0 ? pVertices[pIndices[0]] : vectorf(zero); ((matrix3x3RM&)eigen_axes[0]).SetIdentity(); return; } mean /= sum; // calculate covariance matrix for(i=0; i pVertices,const index_t *pIndices,int nTris, const vectorr *eigen_axes,const vectorr ¢er, int flags, float tolerance, primitive *&pprim) { static cylinder acyl; static box abox; static sphere asphere; int i,j,ibest; real error_max[3],error_avg[4],locerror,locarea; if (flags & mesh_approx_cylinder) { float r[3],h[3],area[2],zloc,rinv,hinv; matrix3x3f Basis = (matrix3x3RM&)eigen_axes[0]; vectorf axis,ptloc,n,ptmin,ptmax,c; int iz,bBest,itype; error_avg[3]=(real)1E10; ibest=3; ptmin=ptmax = Basis*pVertices[pIndices[0]]; for(i=1; i1E-5) locerror = max(locerror, fabs_tpl(((p0-center)*n)/locarea-r)*rinv); error_max[0] = max(error_max[0],locerror); error_avg[0] += locerror*locarea; area += locarea; } error_avg[0] /= area; if (error_max[0]Basis.GetRow(0)-dir*(dir*pbox->Basis.GetRow(0))).len2()*pbox->size[0]; proj = (pbox->Basis.GetRow(1)-dir*(dir*pbox->Basis.GetRow(1))).len2()*pbox->size[1]; i = isneg(maxproj-proj); maxproj = max(proj,maxproj); proj = (pbox->Basis.GetRow(2)-dir*(dir*pbox->Basis.GetRow(2))).len2()*pbox->size[2]; i |= isneg(maxproj-proj)<<1; i &= 2|(i>>1^1); pextbox->Basis.SetRow(2,dir); pextbox->Basis.SetRow(0,(pbox->Basis.GetRow(i)-dir*(dir*pbox->Basis.GetRow(i))).normalized()); pextbox->Basis.SetRow(1, pextbox->Basis.GetRow(2)^pextbox->Basis.GetRow(0)); pextbox->bOriented = 1; matrix3x3f mtx = pextbox->Basis*pbox->Basis.T(); (pextbox->size = mtx.Fabs()*pbox->size).z += fabs_tpl(step)*0.5f; pextbox->center = pbox->center + dir*(step*0.5f); } real RotatePointToPlane(const vectorr &pt, const vectorr &axis,const vectorr ¢er, const vectorr &n,const vectorr &origin) { vectorr ptc,ptz,ptx,pty; real kcos,ksin,k,a,b,c,d; ptc = pt-center; ptz = axis*(axis*ptc); ptx = ptc-ptz; pty = axis^ptx; kcos = ptx*n; ksin = pty*n; k = (ptz+center-origin)*n; a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c; if (d>=0) return asin_tpl((sqrt_tpl(d)*sgnnz(b)-b)/a); else return 0; } void get_xqs_from_matrices(float *pMtx3x3,float *pMtx3x3T,float *pMtx4x4,float *pMtx4x4T, vectorf &pos,quaternionf &q,float &scale) { if (pMtx4x4) { matrix3x3in4x4f &mtx((matrix3x3in4x4f&)*pMtx4x4); scale = mtx.GetRow(0).len(); q = quaternionf(mtx/scale); pos = mtx.GetColumn(3); } else if (pMtx4x4T) { matrix3x3in4x4Tf &mtx((matrix3x3in4x4Tf&)*pMtx4x4T); scale = mtx.GetRow(0).len(); q = quaternionf(mtx/scale); pos = mtx.GetColumn(3); } else if (pMtx3x3) { matrix3x3f &mtx((matrix3x3f&)*pMtx3x3); scale = mtx.GetRow(0).len(); q = quaternionf(mtx/scale); } else if (pMtx3x3T) { matrix3x3Tf &mtx((matrix3x3Tf&)*pMtx3x3); scale = mtx.GetRow(0).len(); q = quaternionf(mtx/scale); } } float frand(float range) { return rand()*(1.0/RAND_MAX)*range; } inline int get_neighb(int iTri,int iEdge, char *pCellDiv,int szx) { static int offsx[8] = { 0,-1, 0, 1,-1, 0, 1, 0 }; static int offsy[8] = { 1, 0,-1, 0, 0,-1, 0, 1 }; static int buddytri[16] = { 1,1,0,0,1,0,0,1, 0,1,1,0,1,1,0,0 }; if (iEdge==2) return iTri^1; int i = pCellDiv[iTri>>1]<<2 | (iTri&1)<<1 | iEdge&1; int iBuddyCell = (iTri>>1)+offsx[i]+offsy[i]*szx; return iBuddyCell*2 + buddytri[pCellDiv[iBuddyCell]<<3 | i]; } inline void get_edge_ends(int iTri,int iEdge, int &iend0,int &iend1, char *pCellDiv,int szx) { int i = pCellDiv[iTri>>1]+(iTri&1^1)*2+iEdge & 3; iend0 = (iTri>>1) + (i>>1)*szx + (i&1 ^ i>>1); i = pCellDiv[iTri>>1]+(iTri&1^1)*2+inc_mod3[iEdge] & 3; iend1 = (iTri>>1) + (i>>1)*szx + (i&1 ^ i>>1); } inline void output_point(vector2df *&ptout,int &nOut,int &nOutAlloc, const vector2df &pt) { if (nOut==nOutAlloc) { vector2df *tmp = ptout; memcpy(ptout=new vector2df[nOutAlloc+=32], tmp, nOut*sizeof(vector2df)); delete[] tmp; } ptout[nOut++] = pt; } int BreakPolygon(vector2df *ptSrc,int nPt, int nCellx,int nCelly, int maxPatchTris, vector2df *&ptout,int *&nPtOut, float jointhresh,int seed) { int i,j,k,i0,i1,ix,iy,nPatches,nSeedTris,nPatchTris,iTri,iTriNew,nCells,ihead,itail,ipt0,ipt1,nOut,iMotherPatch,szQueue,nPatchPt, nOutAlloc,bOut,iEdge,iPatch,iCurPatch,ilist[32],nInters,iPass,ix0,iy0,ix1,iy1,bHasInclusions,nPatchesOut,iExit,iEdge0,ipt,iEnter; vector2di sz; vector2df step,rstep,pt0,pt1,d0,d1,dc,ptmin,ptmax; float snap,rsnap; quotientf ytest,ymin,tlist[32],t0,t1; vector2df *ptin,*pt; int *pTris,*pGrid,*pHash,*queue,*pSeedTris,*pPatchSeeds,*pPatchMothers; char *pCellDiv; sz.set(nCellx+3,nCelly+3); for(i=1,ptmin=ptmax=ptSrc[0]; i>2; szQueue<<=1); queue = new int[szQueue]; pSeedTris = new int[nCells*2]; pPatchSeeds = new int[nCells*2]; pPatchMothers = new int[nCells*2]; memset(pGrid,0,sizeof(int)*(nCells+1)); if (seed!=-1) srand((unsigned int)seed); for(i=0;i=0;i--) { pCellDiv[i] = rand()&1; // randomly choose the way each cell is split pTris[i*2] = pTris[i*2+1] = -1; } // mark borders for(ix=0;ix>1)+(sz.x>>1)*sz.x)*2]=0; itail=0; ihead=1; nSeedTris=0; nPatches=0; do { nPatchTris = float2int(frand(maxPatchTris)-0.5f); // request random number of triangles for this patch for(i=0;i<3;i++) if (pTris[iTri=get_neighb(queue[itail],i, pCellDiv,sz.x)]==-1) pTris[pSeedTris[nSeedTris++] = iTri] = -2; // immediately queue neighbours as potential subsequent patch seeds if (nPatchTris>0) do { // grow iCurPatch around a seed triangle iTri = queue[itail]; itail = itail+1 & szQueue-1; if (pTris[iTri]<0) { if (frand(1)>jointhresh) { pTris[iTri] = nPatches; nPatchTris--; pPatchSeeds[nPatches] = iTri; } else if (pTris[iTri]==-1) pTris[pSeedTris[nSeedTris++] = iTri] = -2; } if (pTris[iTri]==nPatches) for(i=0;i<3;i++) if (pTris[get_neighb(iTri,i, pCellDiv,sz.x)]<0) { queue[ihead] = get_neighb(iTri,i, pCellDiv,sz.x); ihead = ihead+1 & szQueue-1; } } while(nPatchTris>0 && ihead!=itail); pPatchMothers[nPatches++] = -1; for(i=j=0;i=-1) { pTris[queue[0]=pPatchSeeds[iCurPatch]] |= 1<<30; itail=0; ihead=1; iMotherPatch=-1; do { iTri = queue[itail]; itail = itail+1 & szQueue-1; for(iEdge=0;iEdge<3;iEdge++) { iPatch = pTris[iTriNew = get_neighb(iTri,iEdge ,pCellDiv,sz.x)] & ~(1<<30); if (pPatchMothers[iCurPatch]>=0) // assign tri to outer patch, if it exists pTris[iTri] = pPatchMothers[iCurPatch] | 1<<30; if (iPatch!=iCurPatch && iPatch=0) { pPatchMothers[pPatchMothers[iCurPatch]] = -1; // 'needs recheck' state pPatchMothers[iCurPatch] = -3; // 'always ignore this patch from now on' state bHasInclusions = 1; } else { if (iEdge==3) { pPatchMothers[iCurPatch] = iMotherPatch; bHasInclusions = 1; } else pPatchMothers[iCurPatch] = -2; // 'checked' state } } for(i=nCells*2-1;i>=0;i--) pTris[i]&=~(1<<30); if (bHasInclusions) do { // merge nested inclusions for(i=j=0;i=0 && pPatchMothers[pPatchMothers[i]]>=0) { pPatchMothers[i] = pPatchMothers[pPatchMothers[i]]; j++; } } while(j); } while(bHasInclusions); nPtOut = new int[nPatches]; ptout = new vector2df[nOutAlloc=max(16,((sz.x-2)*(sz.y-2)/nPatches)>>2)]; nPatchesOut = nOut = 0; // generate pieces geometries by intersecting patches with the source polygon for(iCurPatch=0; iCurPatchpt[ipt0].y && ytest=0;i0--) for(i1=iszero(iy)^1;i1>=0;i1--) for(i=pGrid[ipt0+(ix&-i0)+(iy&-i1)]; ij;k--) { tlist[k]=tlist[k-1]; ilist[k]=ilist[k-1]; } tlist[j]=t0; ilist[j]=pHash[i]; nInters++; } } for(i=0;i=0 && iExit!=ilist[i]) do { iExit = iExit+1&~-isneg(nPt-iExit-2); output_point(ptout,nOut,nOutAlloc, ptin[iExit]+ptmin); } while(iExit!=ilist[i]); if (iEnter<0) iEnter = ilist[i]; } else iExit = ilist[i]; // add intersection point to output output_point(ptout,nOut,nOutAlloc, pt[ipt0]+(pt[ipt1]-pt[ipt0])*tlist[i].val()+ptmin); bOut ^= 1; } if (!bOut) output_point(ptout,nOut,nOutAlloc, pt[ipt1]+ptmin); do { iEdge = inc_mod3[iEdge]; iTriNew = get_neighb(iTri,iEdge ,pCellDiv,sz.x); if (pTris[iTriNew]!=iCurPatch) break; for(iEdge=0; iEdge<2 && get_neighb(iTriNew,iEdge ,pCellDiv,sz.x)!=iTri; iEdge++); iTri = iTriNew; } while (true); } while(iTri!=pPatchSeeds[iCurPatch] || iEdge!=iEdge0); if (bOut && iEnter>=0 && iExit!=iEnter) do { iExit = iExit+1&~-isneg(nPt-iExit-2); output_point(ptout,nOut,nOutAlloc, ptin[iExit]+ptmin); } while(iExit!=iEnter); if (nPatchPt = nOut-nPatchPt) nPtOut[nPatchesOut++] = nPatchPt; } delete[] pGrid; delete[] pHash; delete[] ptin; delete[] pt; delete[] pTris; delete[] pCellDiv; delete[] queue; delete[] pSeedTris; delete[] pPatchSeeds; delete[] pPatchMothers; return nPatchesOut; } int GetProjCubePlane(const vectorf &pt) { int iPlane = isneg(fabsf(pt.x)-fabsf(pt.y)); iPlane |= isneg(fabsf(pt[iPlane])-fabsf(pt.z))<<1; iPlane &= 2|(iPlane>>1^1); return iPlane<<1 | isnonneg(pt[iPlane]); } void RasterizePolygonIntoCubemap(const vectorf *pt,int npt, int iPass, int *pGrid[6],int nRes, float rmin,float rmax,float zscale) { int iPlane,iPlaneEnd,ipt,ipt1,i,j,iBrd[2],iBrdNext[2],idx,lxdir,iSign,ixlim[2],iylim,imask,idcell,iz, irmin,iyend,iOrder,nCells,ixleft,iEnter,nPlanes; vectori ic; vector2di icell,ibound; vectorf nplane,n,rn; vector2df ptint[2],dp[2]; float kres,krres,koffs,dz,dp0[2],denom; quotientf z; struct cube_plane { int iEnter,iExit; float minz; int npt; vector2df pt[32]; }; static cube_plane planes[6]; nplane = pt[1]-pt[0] ^ pt[2]-pt[0]; if (isnonneg(nplane*pt[0])^iPass) return; kres = 0.5f*nRes; krres = 2.0f/nRes; koffs = 1.0f-krres*0.5f; irmin = float2int(rmin*zscale); for(i=0;i<6;i++) { planes[i].npt=0; planes[i].iExit=-1; planes[i].minz = rmax; } z.x = pt[0]*nplane; for(i=0;i<3;i++) for(ipt=0;ipt>31; iPlane = GetProjCubePlane(pt[ipt]); iPlaneEnd = GetProjCubePlane(pt[ipt1]); n = pt[ipt]^pt[ipt1]; rn.zero(); ic.z = iPlane>>1; denom = 1.0f/(fabsf(pt[ipt][ic.z])+isneg(fabsf(pt[ipt][ic.z])-1E-5f)*1E4f); // store the starting point planes[iPlane].pt[planes[iPlane].npt++&31].set(pt[ipt][inc_mod3[ic.z]]*denom, pt[ipt][dec_mod3[ic.z]]*denom); for(nPlanes=0; iPlane!=iPlaneEnd && nPlanes<6; nPlanes++) { ic.z = iPlane>>1; iSign = ((iPlane&1)<<1)-1; ic.x = inc_mod3[ic.z]; ic.y = dec_mod3[ic.z]; ibound.x = sgnnz(n[ic.y])*iSign; ibound.y = -sgnnz(n[ic.x])*iSign; ptint[0].x = ibound.x; // intersect line with face boundary conditions and take the intersection that is inside face ptint[0].y = -n[ic.z]*iSign-n[ic.x]*ptint[0].x; // only check boundaries that lie farther along ccw movement of line around origin-edge plane normal ptint[1].y = ibound.y; ptint[1].x = -n[ic.z]*iSign-n[ic.y]*ptint[1].y; idx = inrange(ptint[1].x, -n[ic.x],n[ic.x]); if (rn[ic[idx^1]]==0) rn[ic[idx^1]] = 1.0f/(n[ic[idx^1]]+isneg(fabsf(n[ic[idx^1]])-1E-5f)*1E4f); ptint[idx][idx^1] *= rn[ic[idx^1]]; // store ptint[idx] in iPlane's point list planes[iPlane].pt[planes[iPlane].npt++&31] = ptint[idx]; planes[iPlane].iExit = idx+1-ibound[idx]; iPlane = ic[idx]<<1 | ibound[idx]+1>>1; iEnter = (idx^1)+1-iSign; if (planes[iPlane].iExit>=0) { // add corner points between the last exit point and this enter point iOrder = (((iPlane&1)<<1)-1)*((iPass<<1)-1); j = iOrder>>31; for(i=planes[iPlane].iExit; i!=iEnter; i=i+iOrder&3) planes[iPlane].pt[planes[iPlane].npt++&31].set(1-((i+j^i+j<<1)&2),1-(i+j&2)); planes[iPlane].iExit = -1; } else planes[iPlane].iEnter = iEnter; // store ptint[idx] in the new iPlane's point list (transform it to the new iPlane beforehand) ptint[idx][idx] = ptint[idx][idx^1]; ptint[idx][idx^1] = iSign; planes[iPlane].pt[planes[iPlane].npt++&31] = ptint[idx]; if (planes[iPlane].npt>32) planes[iPlane].npt = 0; // should not happen } } for(iPlane=nCells=i=0,ic.z=6;iPlane<6;iPlane++) { j = iszero(planes[iPlane].npt)^1; nCells += j; j <<= iPlane>>1; // j = plane axis bit ic.z -= (iPlane>>1)+1 & -(j & (i&j^j))>>31; // subtract plane axis index+1 from the sum if this axis hasn't been encountered yet i |= j; // accumulate used axes mask } if (nCells==4 && ic.z>=1 && ic.z<=3) { // we have 4 sides that form a 'ring', meaning one (and only one) axis is unaffected edges ic.z--; iPlane = isneg(nplane[ic.z])^iPass | ic.z<<1; iOrder = (((iPlane&1)<<1)-1)*((iPass<<1)-1); j = iOrder>>31; for(i=0; planes[iPlane].npt<4; i=i+iOrder&3) planes[iPlane].pt[planes[iPlane].npt++&31].set(1-((i+j^i+j<<1)&2),1-(i+j&2)); } // rasterize resulting polygons in each plane for(iPlane=nCells=0;iPlane<6;iPlane++) { iOrder = (((iPlane&1)<<1)-1)*((iPass<<1)-1); j = iOrder>>31; if (planes[iPlane].iExit>=0) // close pending exits for(i=planes[iPlane].iExit; i!=planes[iPlane].iEnter; i=i+iOrder&3) planes[iPlane].pt[planes[iPlane].npt++&31].set(1-((i+j^i+j<<1)&2),1-(i+j&2)); if (planes[iPlane].npt && planes[iPlane].npt<32) { ic.z = iPlane>>1; ic.x = inc_mod3[ic.z]; ic.y = dec_mod3[ic.z]; iSign = (iPlane&1)*2-1; dz = nplane[ic.x]*krres; for(i=1,iBrd[0]=iBrd[1]=0; i>31; // wrap -1 to npt-1 and npt to 0 iBrdNext[0] &= iBrdNext[0]-planes[iPlane].npt>>31; iBrdNext[1] = iBrd[1]-iOrder; iBrdNext[1] += planes[iPlane].npt & iBrdNext[1]>>31; // wrap -1 to npt-1 and npt to 0 iBrdNext[1] &= iBrdNext[1]-planes[iPlane].npt>>31; idx = isneg(planes[iPlane].pt[iBrdNext[0]].y-planes[iPlane].pt[iBrdNext[1]].y); dp[0] = planes[iPlane].pt[iBrdNext[0]]-planes[iPlane].pt[iBrd[0]]; dp0[0] = (dp[0]^planes[iPlane].pt[iBrd[0]]+vector2df(koffs,koffs))*kres; dp[1] = planes[iPlane].pt[iBrdNext[1]]-planes[iPlane].pt[iBrd[1]]; dp0[1] = (dp[1]^planes[iPlane].pt[iBrd[1]]+vector2df(koffs,koffs))*kres; lxdir = sgnnz(dp[0].x); ixlim[0] = min(nRes-1,max(0,float2int((min(planes[iPlane].pt[iBrd[0]].x, planes[iPlane].pt[iBrdNext[0]].x)+koffs)*kres))); ixlim[1] = min(nRes-1,max(0,float2int((max(planes[iPlane].pt[iBrd[1]].x, planes[iPlane].pt[iBrdNext[1]].x)+koffs)*kres))); icell.y = max(icell.y,iyend); iylim = min(nRes-1,max(iyend,float2int((planes[iPlane].pt[iBrdNext[idx]].y+koffs)*kres))); do { // search left or right (dep. on sgn(dp.x)) from the left border to find the leftmost filled cell // left: iterate while point is inside and x!=xmin-1, increment x after loop; right: while point is outside and x!=xmax for(icell.x=ixleft; isneg((dp[0]^icell)*lxdir-dp0[0]*lxdir) & (iszero(ixlim[lxdir+1>>1]+(lxdir>>31)-icell.x)^1); icell.x+=lxdir); icell.x -= lxdir>>31; ixleft = icell.x; // search right from the leftmost cell to the end of the right border, filling data z.y = nplane[ic.x]*(icell.x*krres-koffs)+nplane[ic.y]*(icell.y*krres-koffs)+nplane[ic.z]*iSign; idcell = icell.x+icell.y*nRes; // 1st (front face) pass output: // iz>31; iz = (iz|imask) & (1u<<31)-1; pGrid[iPlane][idcell] = min(pGrid[iPlane][idcell]&(1u<<31)-1,iz) | (pGrid[iPlane][idcell] | imask)&(1<<31); } else for(; isneg((dp[1]^icell)-dp0[1]) & isneg(icell.x-ixlim[1]-1); icell.x++,z.y+=dz,idcell++) { iz = float2int(max(planes[iPlane].minz,min(fabsf(z.val()),rmax))*zscale); nCells++; //pGrid[iPlane][idcell] &= irmin-iz>>31 | (1u<<31)-1; imask = iz-irmin>>31; iz = (iz|imask) & (1u<<31)-1; pGrid[iPlane][idcell] = min(pGrid[iPlane][idcell]&(1u<<31)-1,iz) | (pGrid[iPlane][idcell] & ~imask)&(1<<31); } } while(--icell.y>=iylim); iBrd[idx] = iBrdNext[idx]; ixleft = ixleft&-idx | ixlim[0]&~-idx; // update ixleft if the left branch advances } while(iylim>iyend); } } if (nCells==0) { // do not allow objects to take no rasterized space iPlane = GetProjCubePlane(pt[0]); ic.z = iPlane>>1; ic.x = inc_mod3[ic.z]; ic.y = dec_mod3[ic.z]; denom = 1.0f/fabsf(pt[0][ic.z]); icell.x = min(nRes-1,max(0,float2int((pt[0][ic.x]*denom+koffs)*kres))); icell.y = min(nRes-1,max(0,float2int((pt[0][ic.y]*denom+koffs)*kres))); idcell = icell.x+icell.y*nRes; iz = float2int(min(fabsf(pt[0][ic.z]),rmax)*zscale); if (iPass==0) { imask = iz-irmin>>31; iz = (iz|imask) & (1u<<31)-1; pGrid[iPlane][idcell] = min(pGrid[iPlane][idcell]&(1u<<31)-1,iz) | (pGrid[iPlane][idcell] | imask)&(1<<31); } else pGrid[iPlane][idcell] &= irmin-iz>>31 | (1u<<31)-1; } } inline int get_cubemap_cell_buddy(int idCell,int iBuddy, int nRes) { int idx,istep,bWrap,idBuddy,idWrappedBuddy; vectori icell,iaxis; idx = iBuddy&1; // step axis: 0 - local x, 1 - local y istep = (iBuddy&2)-1; // step direction icell[idx] = (idCell>>8*idx & 0xFF)+istep; // unpacked cell (x,y,z) icell[idx^1] = idCell>>8*(idx^1) & 0xFF; icell.z = nRes-1 & -(idCell>>16&1); iaxis.z = idCell>>17; iaxis.x = inc_mod3[iaxis.z]; iaxis.y = dec_mod3[iaxis.z]; idBuddy = icell.x | icell.y<<8 | idCell&0x70000; idWrappedBuddy = icell[idx^1]<<8*idx | icell.z<<8*(idx^1) | iaxis[idx]<<17 | istep+1<<15; bWrap = icell[idx]>>31 | nRes-1-icell[idx]>>31; return idWrappedBuddy&bWrap | idBuddy&~bWrap; } void GrowAndCompareCubemaps(int *pGridOcc[6],int *pGrid[6],int nRes, int nGrow, int &nCells,int &nOccludedCells) { struct cell_info { int idcell; int z; }; int i,iPlane,icell,icell1,idcell,idcell1,ix,iy,bUsed,bVisible,ipass,ihead=0,itail=0,itailend,imaxz=(1u<<31)-1; cell_info queue[4096]; nCells = nOccludedCells = 0; for(iPlane=0;iPlane<6;iPlane++) { for(iy=0;iy>31) for(i=0,idcell=ix|iy<<8|iPlane<<16;i<4;i++) { // enqueue neighbouring unused cells idcell1 = get_cubemap_cell_buddy(idcell, i, nRes); icell1 = (idcell1>>8&0xFF)*nRes + (idcell1&0xFF); if (pGrid[idcell1>>16][icell1]>=imaxz) { queue[ihead].idcell = idcell1; queue[ihead].z = pGrid[iPlane][icell]; ihead = ihead+1 & sizeof(queue)/sizeof(queue[0])-1; } } } } for(ipass=0;ipass>8&0xFF)*nRes + (idcell&0xFF); iPlane = idcell>>16; if (pGrid[iPlane][icell]>8&0xFF)*nRes + (idcell1&0xFF); if (pGrid[idcell1>>16][icell1]>=imaxz) { queue[ihead].idcell = idcell1; queue[ihead].z = pGrid[iPlane][icell]; ihead = ihead+1 & sizeof(queue)/sizeof(queue[0])-1; } } } } void debug_calc_tri_resistance(const vectorf *pt,const vectorf &n, const vectorf &v,const vectorf &w, vectorf &P,vectorf &L) { float square = (pt[1]-pt[0] ^ pt[2]-pt[0]).len2()*0.25f; if (square=d;i0++); if (i0==nsrc) return 0; for(iCount=ndst=0;iCount>31; ptdst[ndst] = ptsrc[i0]; ndst += isneg(ptsrc[i0]*n-d); if ((ptsrc[i0]*n-d)*(ptsrc[i1]*n-d)<0) ptdst[ndst++] = ptsrc[i0]+(ptsrc[i1]-ptsrc[i0])*((d-ptsrc[i0]*n)/((ptsrc[i1]-ptsrc[i0])*n)); } return ndst; } void CalcMediumResistance(const vectorf *ptsrc,int npt, const vectorf& n, const plane &waterPlane, const vectorf &vworld,const vectorf &wworld,const vectorf &com, vectorf &P,vectorf &L) { int i; vectorf pt0[16],pt[16],v,w,rotax,dP(zero),dL(zero); float x0,y0,dx,dy,Fxy,Fxx,Fxxy,Fxyy,Fxxx,square=0,sina; npt = crop_polygon_with_plane(ptsrc,npt, pt0, waterPlane.n,waterPlane.origin*waterPlane.n); for(i=0;i0.001f) rotax/=sina; else rotax.Set(1,0,0); v = vworld.rotated(rotax,n.z,sina); w = wworld.rotated(rotax,n.z,sina); for(i=0;i>j)&1; } }; static ComputeBitCount now; int bin2ascii(const unsigned char *pin,int sz, unsigned char *pout) { int a0,a1,a2,i,j,nout,chr[3]; for(i=nout=0;i>2; chr[1] = a0<<4&0x30 | (a1>>4)&0x0F; chr[2] = a1<<2&0x3C | a2>>6&0x03; chr[3] = a2&0x03F; for(j=0;j<4;j++) *pout++ = mapsymb(chr[j],g_rngb2a,5); } return nout; } int ascii2bin(const unsigned char *pin,int sz, unsigned char *pout) { int a0,a1,a2,a3,i,nout; for(i=nout=0;i>4; *pout++ = a1<<4&0xF0 | a2>>2&0x0F; *pout++ = a2<<6&0xC0 | a3; } return nout; } int CoverPolygonWithCircles(strided_pointer pt,int npt,bool bConsecutive, const vector2df ¢er, vector2df *¢ers,float *&radii, float minCircleRadius) { intptr_t imask; int i,nCircles=0,nSkipped; vector2df pts[3],bisector; float r,area,len2; ptitem2d *pdata,*plist,*pvtx,*pvtx_max,*pvtx_left,*pvtx_right; static vector2df g_centers[32]; static float g_radii[32]; centers = g_centers; radii = g_radii; if (npt<2) return 0; pdata = plist = new ptitem2d[npt]; for(i=0,r=0; i>31); pdata[i].prev = pdata+i-1+(npt & i-1>>31); r = max(r, pdata[i].pt.len2()); } if (r < sqr(minCircleRadius)) { g_centers[0] = center; g_radii[0] = sqrt_tpl(r); return 1; } if (!bConsecutive) { edgeitem *pcontour = new edgeitem[npt],*pedge; if (qhull2d(pdata,npt,pcontour)) { plist=pvtx=(pedge=pcontour)->pvtx; npt=0; do { pvtx->next = pedge->next->pvtx; pvtx->prev = pedge->prev->pvtx; pvtx = pvtx->next; npt++; } while((pedge=pedge->next)!=pcontour); } delete[] pcontour; } for(i=0,area=0,pvtx=plist; inext) area += pvtx->pt^pvtx->next->pt; if (fabs_tpl(area*0.5f-r*pi) < area*0.4f) { // one circle fits the figure quite ok g_centers[0] = center; g_radii[0] = sqrt_tpl(r); return 1; } do { pvtx=pvtx_max=plist; do { // find the farthest from the center vertex imask = -isneg(pvtx_max->pt.len2() - pvtx->pt.len2()); pvtx_max = (ptitem2d*)((intptr_t)pvtx_max&~imask | (intptr_t)pvtx&imask); } while((pvtx=pvtx->next)!=plist); len2 = pvtx_max->pt.len2(); // find the farthest from the center vertex in +30 degrees vicinity of the global maximum for(pvtx=(pvtx_left=pvtx_max)->next; pvtx!=pvtx_max && sqr(pvtx->pt^pvtx_max->pt) < 0.25f*pvtx->pt.len2()*len2 && pvtx->pt*pvtx_max->pt>0; pvtx=pvtx->next) { imask = -((intptr_t)isneg(pvtx_left->pt.len2() - pvtx->pt.len2()) | iszero((intptr_t)pvtx_left-(intptr_t)pvtx_max)); pvtx_left = (ptitem2d*)((intptr_t)pvtx_left&~imask | (intptr_t)pvtx&imask); } // find the farthest from the center vertex in -30 degrees vicinity of the global maximum for(pvtx=(pvtx_right=pvtx_max)->prev; pvtx!=pvtx_max && sqr(pvtx->pt^pvtx_max->pt) < 0.25f*pvtx->pt.len2()*len2 && pvtx->pt*pvtx_max->pt>0; pvtx=pvtx->prev) { imask = -((intptr_t)isneg(pvtx_right->pt.len2() - pvtx->pt.len2()) | iszero((intptr_t)pvtx_right-(intptr_t)pvtx_max)); pvtx_right = (ptitem2d*)((intptr_t)pvtx_right&~imask | (intptr_t)pvtx&imask); } // find a circle w/ center on left-right bisector that covers all 3 max vertices bisector = (pvtx_left->pt+pvtx_right->pt).normalized(); pts[0]=pvtx_left->pt; pts[1]=pvtx_right->pt; pts[2]=pvtx_max->pt; for(i=0,r=0;i<3;i++) { float x = bisector*pts[i]; r = max(r,(sqr(x)+sqr(bisector^pts[i]))/(2*x)); } g_centers[nCircles] = center+bisector*r; g_radii[nCircles++] = r; // remove all vertices that lie inside (or close enough to) this new circle for(i=nSkipped=0,pvtx=plist; inext) if ((pvtx->pt+center-g_centers[nCircles-1]).len2()next->prev = pvtx->prev; pvtx->prev->next = pvtx->next; nSkipped++; if (pvtx==plist) { if (pvtx->prev!=pvtx) plist = pvtx->prev; else goto allcircles; } } npt -= nSkipped; } while(nSkipped && nCircles=1u<0) stm.WriteNumberInBits(num,i*2); } void WritePacked(CStream &stm, uint64 num) { WritePacked(stm,(int)(num & 0xFFFFFFFF)); WritePacked(stm,(int)(num>>32 & 0xFFFFFFFF)); } void ReadPacked(CStream &stm,int &num) { int i; num=0; stm.ReadNumberInBits(i,5); if(i>16) CryError("ReadPacked i==%i", i); if (i>0) stm.ReadNumberInBits(num,i*2); } void ReadPacked(CStream &stm,uint64 &num) { int ilo,ihi; ReadPacked(stm,ilo); ReadPacked(stm,ihi); num = (uint64)(unsigned int)ihi<<32 | (uint64)(unsigned int)ilo; } void WriteCompressedPos(CStream &stm, const vectorf &pos, bool bCompress) { if(!inrange(pos.x,0.0f,2048.0f) || !inrange(pos.y,0.0f,2048.0f) || !inrange(pos.z,0.0f,512.0f) || !bCompress) { stm.Write(false); stm.Write(pos); } else { stm.Write(true); stm.WriteNumberInBits(float2int(pos.x*512.0f),20); stm.WriteNumberInBits(float2int(pos.y*512.0f),20); stm.WriteNumberInBits(float2int(pos.z*512.0f),18); } //stm.WritePkd(CStreamData_WorldPos(const_cast(pos))); } void ReadCompressedPos(CStream &stm, vectorf &pos, bool &bWasCompressed) { stm.Read(bWasCompressed); if (bWasCompressed) { unsigned int ix,iy,iz; stm.ReadNumberInBits(ix, 20); pos.x = ix*(1.0f/512); stm.ReadNumberInBits(iy, 20); pos.y = iy*(1.0f/512); stm.ReadNumberInBits(iz, 18); pos.z = iz*(1.0f/512); } else stm.Read(pos); //stm.ReadPkd(CStreamData_WorldPos(pos)); } vectorf CompressPos(const vectorf &pos) { if(!inrange(pos.x,0.0f,2048.0f) || !inrange(pos.y,0.0f,2048.0f) || !inrange(pos.z,0.0f,512.0f)) return pos; return vectorf(float2int(pos.x*512.0f)*(1.0f/512), float2int(pos.y*512.0f)*(1.0f/512), float2int(pos.z*512.0f)*(1.0f/512)); //return CStreamData_WorldPos(const_cast(pos)).GetCompressed(); } bool getCompressedQuat(const quaternionf &q, Vec3_tpl &res) { vectorf angles = Ang3::GetAnglesXYZ(matrix3x3f(q)); bool bGimbalLocked; if (bGimbalLocked = fabs_tpl(angles.y)>pi*0.5f-0.03f) angles = Ang3::GetAnglesXYZ(matrix3x3f(q*GetRotationAA((float)pi/6,vectorf(0,1,0)))); res.x = max(-32768,min(32767,float2int(angles.x*(32767/pi)))); res.y = max(-32768,min(32767,float2int(angles.y*(32767/(pi*0.5f))))); res.z = max(-32768,min(32767,float2int(angles.z*(32767/pi)))); return bGimbalLocked; } void WriteCompressedQuat(CStream &stm, const quaternionf &q) { Vec3_tpl sangles; stm.Write(getCompressedQuat(q,sangles)); stm.Write(sangles.x); stm.Write(sangles.y); stm.Write(sangles.z); } void ReadCompressedQuat(CStream &stm,quaternionf &q) { bool bGimbalLocked; stm.Read(bGimbalLocked); Vec3_tpl sangles; stm.Read(sangles.x); stm.Read(sangles.y); stm.Read(sangles.z); q = Quat::GetRotationXYZ(vectorf(sangles.x*(pi/32767),sangles.y*(pi*0.5f/32767),sangles.z*(pi/32767))); if (bGimbalLocked) q *= GetRotationAA((float)-pi/6,vectorf(0,1,0)); } quaternionf CompressQuat(const quaternionf &q) { Vec3_tpl sangles; bool bGimbalLocked = getCompressedQuat(q,sangles); quaternionf qres = Quat::GetRotationXYZ(vectorf(sangles.x*(pi/32767),sangles.y*(pi*0.5f/32767),sangles.z*(pi/32767))); if (bGimbalLocked) qres *= GetRotationAA((float)-pi/6,vectorf(0,1,0)); return qres; }