//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: brushface.cpp // Version: v1.00 // Created: 8/7/2002 by Timur. // Compilers: Visual Studio.NET // Description: // ------------------------------------------------------------------------- // History: Based on Andrey's Indoor editor. // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "BrushFace.h" #include "BrushPlane.h" #include "BrushPoly.h" #include "Brush.h" #include "BrushMtl.h" #include // Local namespace. namespace { //! Creates boundary plane. inline void CreateBoundaryPlane( SBrushPlane *src, Vec3d& p1, Vec3d& p2, SBrushPlane *dst ) { Vec3d vv; vv = p2 - p1; dst->normal = src->normal ^ vv; dst->normal.Normalize(); dst->dist = dst->normal | p1; } //static Vec3d m_TexVecs[2]; //static float m_TexShift[2]; } ////////////////////////////////////////////////////////////////////////// // // SBrushFace implementation. // ////////////////////////////////////////////////////////////////////////// SBrushFace& SBrushFace::operator = (const SBrushFace& f) { int i; m_Prefabs = NULL; for (i=0; i<3; i++) { m_PlanePts[i] = f.m_PlanePts[i]; } m_TexInfo = f.m_TexInfo; m_Plane = f.m_Plane; if (f.m_Poly) { m_Poly = new SBrushPoly; *m_Poly = *f.m_Poly; } m_color = f.m_color; m_mtl = f.m_mtl; m_RE = NULL; return *this; } ////////////////////////////////////////////////////////////////////////// void SBrushFace::MakePlane() { m_Plane.Make( m_PlanePts[0],m_PlanePts[1],m_PlanePts[2] ); } ////////////////////////////////////////////////////////////////////////// void SBrushFace::TextureVectors(Vec3d& tVecx, Vec3d& tVecy, float& tShiftx, float& tShifty) { Vec3d pvecs[2]; int sv, tv; float ang, sinv, cosv; float ns, nt; int i; SMapTexInfo *td; td = &m_TexInfo; //e = m_shader; tVecx(0,0,0); tVecy(0,0,0); tShiftx = 0; tShifty = 0; if (!td->scale[0]) td->scale[0] = 0.5; if (!td->scale[1]) td->scale[1] = 0.5; m_Plane.CalcTextureAxis(pvecs[0], pvecs[1], 1); // rotate axis if (td->rotate == 0) { sinv = 0 ; cosv = 1; } else if (td->rotate == 90) { sinv = 1 ; cosv = 0; } else if (td->rotate == 180) { sinv = 0 ; cosv = -1; } else if (td->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = td->rotate / 180 * gf_PI; sinv = sin(ang); cosv = cos(ang); } if (pvecs[0][0]) sv = 0; else if (pvecs[0][1]) sv = 1; else sv = 2; if (pvecs[1][0]) tv = 0; else if (pvecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; if (!i) { tVecx[sv] = ns; tVecx[tv] = nt; } else { tVecy[sv] = ns; tVecy[tv] = nt; } } // scale tVecx /= td->scale[0]; tVecy /= td->scale[1]; // defaults. int texWidth = 32; int texHeight = 32; //@ASK Andrey. if (m_mtl) { ITexPic *tex = m_mtl->GetEditorTexture(); if (tex) { texWidth = tex->GetWidth(); texHeight = tex->GetHeight(); } } // shift tShiftx = td->shift[0] / texWidth; tShifty = td->shift[1] / texHeight; tVecx /= texWidth; tVecy /= texHeight; } ////////////////////////////////////////////////////////////////////////// bool SBrushFace::ClipLine( Vec3d& p1,Vec3d& p2 ) { float d1, d2; d1 = p1.Dot(m_Plane.normal) - m_Plane.dist; d2 = p2.Dot(m_Plane.normal) - m_Plane.dist; if (d1 >= 0 && d2 >= 0) return false; if (d1 <= 0 && d2 <= 0) return true; float dt = d1 / (d1 - d2); if (d1 > 0) p1 = p1 + dt * (p2 - p1); else p2 = p1 + dt * (p2 - p1); return true; } ////////////////////////////////////////////////////////////////////////// void SBrushFace::CalcTexCoords( SBrushVert &v ) { Vec3d tVecx, tVecy; float tShiftx, tShifty; TextureVectors (tVecx, tVecy, tShiftx, tShifty); v.st[0] = (v.xyz.Dot(tVecx)) + tShiftx; v.st[1] = -((v.xyz.Dot(tVecy)) + tShifty); } ////////////////////////////////////////////////////////////////////////// void SBrushFace::DeletePrefabs(void) { /* TPrefabItem *pi, *Next; for (pi=m_Prefabs; pi; pi=Next) { Next = pi->Next; delete pi; } */ m_Prefabs = NULL; } /////////////////////////////////////////////////////////////////////////// float SBrushFace::CalcArea() { int nNumVertices=m_Poly->m_Pts.size(); Vec3d *vTempVecs=new Vec3d [nNumVertices]; for (int k=0;km_Pts[k]; vTempVecs[k]=vOrigVert.xyz; } //k m_fArea=::CalcArea(vTempVecs,nNumVertices,m_Plane.normal); delete [] vTempVecs; return (m_fArea); } /////////////////////////////////////////////////////////////////////////// void SBrushFace::CalcCenter() { m_vCenter(0,0,0); int nNumVertices=m_Poly->m_Pts.size(); for (int k=0;km_Pts[k]; m_vCenter+=vOrigVert.xyz; } //k m_vCenter=m_vCenter/(float)nNumVertices; } ////////////////////////////////////////////////////////////////////////// void SBrushFace::BuildPrefabs_r(SBrushPoly *p, Vec3d& Area, Vec3d& Scale) { int i, i1, i2; Vec3d mins, maxs; Vec3d v, v1, v2; Vec3d vup, vright, vpn, org; SBrushPlane pl; SBrushPoly *front, *back; float size; if (!p) return; p->CalcBounds(mins, maxs); float a0 = Area[0]; float a1 = Area[1]; if (a0 < 2) a0 = 2; if (a1 < 2) a1 = 2; size = 99999.0f; i = -1; for (int n=0; nm_Pts.size(); n++) { float s; v = p->m_Pts[n].xyz - mins; if ((s=v.Length()) < size) { i = n; size = s; } } if (!i) i1 = p->m_Pts.size()-1; else i1 = i-1; i2 = (i+1)%p->m_Pts.size(); v = p->m_Pts[i].xyz; v1 = p->m_Pts[i1].xyz; v2 = p->m_Pts[i2].xyz; vup = v1 - v; vright = v2 - v; float si = vright.Length(); if (si-a0 > 0.1f) { Vec3d sp1, sp2; sp1 = vright; sp1.Normalize(); sp1 = v + sp1 * a0; sp2 = vup; sp2.Normalize(); sp2 = sp1 + sp2 * a1; CreateBoundaryPlane(&m_Plane, sp1, sp2, &pl); p->ClipByPlane(&pl, 0.1f, &front, &back); BuildPrefabs_r(front, Area, Scale); BuildPrefabs_r(back, Area, Scale); if (front) delete front; if (back) delete back; return; } si = vup.Length(); if (si-a1 > 0.1f) { Vec3d sp1, sp2; sp1 = vup; sp1.Normalize(); sp1 = v + sp1 * a1; sp2 = vright; sp2.Normalize(); sp2 = sp1 + sp2 * a0; CreateBoundaryPlane(&m_Plane, sp1, sp2, &pl); p->ClipByPlane(&pl, 0.1f, &front, &back); BuildPrefabs_r(front, Area, Scale); BuildPrefabs_r(back, Area, Scale); if (front) delete front; if (back) delete back; return; } SPrefabItem *pi = new SPrefabItem; //Timur[9/16/2002]pi->Next = NULL; //Timur[9/16/2002]pi->PrevLink =NULL; //Timur[9/16/2002]pi->Link(m_Prefabs); //Timur[7/3/2002] //@ASK Andrey. /* pi->m_Geom = (CREPrefabGeom *)m_shader->m_REs[0]; CModelCgf *m = (CModelCgf *)pi->m_Geom->mModel; */ p->MakePlane(&pl); vpn = pl.normal; vup.Normalize(); vright.Normalize(); vright *= Scale[0]; vup *= Scale[1]; org = v; Matrix44 mat; mat.BuildFromVectors(vright, vup, vpn, org); pi->m_Matrix = mat; } ////////////////////////////////////////////////////////////////////////// SBrushFace::~SBrushFace() { DeletePrefabs(); if (m_Poly) delete m_Poly; if (m_RE) { ReleaseRE(); } } ////////////////////////////////////////////////////////////////////////// void SBrushFace::BuildRE( const Matrix44 &worldTM ) { if (!m_Prefabs) { // Delete previous render element. if (m_RE) ReleaseRE(); CREPolyMesh *re = (CREPolyMesh *)GetIEditor()->GetRenderer()->EF_CreateRE(eDATA_Poly); m_RE = re; //m_RE->m_DynMask = -1; re->m_Plane.n = m_Plane.normal; re->m_Plane.d = m_Plane.dist; re->Srf = this; //Timur[9/16/2002] /* SShader *eft = m_shader->mfGetTemplate(g_Globals.m_TemplateId); if (m_shader && gNE[eft->m_Id].m_TessSize) { m_bTesselated = true; TessSurf(re, this, gNE[eft->m_Id].m_TessSize); } else */ { //m_bTesselated = false; int numPts = m_Poly->m_Pts.size(); re->NumVerts = numPts; re->TriVerts = new SMTriVert[numPts]; re->NumIndices = (numPts-2)*3; re->Indices = new ushort[re->NumIndices]; SBrushVert *v = &m_Poly->m_Pts[0]; for (int i=re->NumVerts-1; i>=0; i--, v++) { re->TriVerts[i].vert = worldTM.TransformPointOLD(v->xyz); re->TriVerts[i].dTC[0] = v->st[0]; re->TriVerts[i].dTC[1] = v->st[1]; re->TriVerts[i].lmTC[0] = v->st[0]; re->TriVerts[i].lmTC[1] = v->st[1]; } ushort *vrtind = re->Indices; for (i=0; im_REs.size()!=0) m_shader->m_REs[0]->mfBuildGeometry(m_shader); */ } void SBrushFace::ReleaseRE() { if (m_RE) { // Needed to delete pointers in same module. CREPolyMesh *re = (CREPolyMesh*)m_RE; if (re->TriVerts) delete []re->TriVerts; if (re->Indices) delete []re->Indices; re->TriVerts = 0; re->Indices = 0; re->NumVerts = 0; re->NumIndices = 0; } } ////////////////////////////////////////////////////////////////////////// void SBrushFace::BuildPrefabs(void) { //@ASK Andrey. /* DeletePrefabs(); if (!m_shader || m_shader->m_REs.size()==0 || m_shader->m_REs[0]->mfGetType() != eDATA_Prefab) return; CREPrefabGeom *pg = (CREPrefabGeom *)m_shader->m_REs[0]; CModelCgf *m = (CModelCgf *)pg->mModel; Vec3d Area = m->m_BBox.max - m->m_BBox.min; Vec3d Scale; Scale[0] = m_TexInfo.scale[0]; Scale[1] = m_TexInfo.scale[1]; Scale[2] = 1.0f; if (gcpCryIndEd->m_wndTextureBar.m_bAutoPrefab) { Vec3d v, v1, v2, vup, vright, mins, maxs; int i, i1, i2; SBrushPoly *p = m_Poly; float size = 99999.0f; p->CalcBounds(mins, maxs); float a0 = Scale[0] * Area[0]; float a1 = Scale[1] * Area[1]; i = -1; for (int n=0; nm_Pts.size(); n++) { float s; v = p->m_Pts[n].xyz - mins; if ((s=v.Length()) < size) { i = n; size = s; } } if (!i) i1 = p->m_Pts.size()-1; else i1 = i-1; i2 = (i+1)%p->m_Pts.size(); v = p->m_Pts[i].xyz; v1 = p->m_Pts[i1].xyz; v2 = p->m_Pts[i2].xyz; vup = v1 - v; vright = v2 - v; float s = vright.Length(); float t = s / a0; int ti = (int)t; float tf = t - ti; if (tf > 0.5f) ti++; if (ti <= 0) ti = 1; Area[0] = s / ti; Scale[0] = Area[0] / (m->m_BBox.max.x - m->m_BBox.min.x); s = vup.Length(); t = s / a1; ti = (int)t; tf = t - ti; if (tf > 0.5f) ti++; if (ti <= 0) ti = 1; Area[1] = s / ti; Scale[1] = Area[1] / (m->m_BBox.max.y - m->m_BBox.min.y); } else { Area[0] *= Scale[0]; Area[1] *= Scale[1]; } BuildPrefabs_r(m_Poly, Area, Scale); */ } ////////////////////////////////////////////////////////////////////////// void SBrushFace::ClipPrefab(SPrefabItem *pi) { //@ASK Andrey. /* CComModel *fr, *md; if (pi->m_Model) md = pi->m_Model; else md = (CComModel *)pi->m_Geom->mModel; fr = md->mfClip(&m_Plane, pi->m_Matrix); if (fr) { if (pi->m_Model) delete md; pi->m_Model = fr; } */ } //////////////////////////////////////////////////////////////////// bool SBrushFace::IsIntersecting(const SBrushPlane &Plane) { if (!m_Poly) return (false); bool bFront=false; bool bBack=false; for (int k=0;km_Pts.size();k++) { Vec3d Vert=m_Poly->m_Pts[k].xyz; float dist=(Plane.normal|Vert)-Plane.dist; if (dist>=0) { if (bBack) return (true); bFront=true; } else { if (bFront) return (true); bBack=true; } } //k return (false); } //////////////////////////////////////////////////////////////////// bool SBrushFace::IsIntersecting(SBrush *Vol) { for (int i=0; im_Faces.size(); i++) { SBrushFace *f = Vol->m_Faces[i]; //check if the face intersect the volume side's plane if (IsIntersecting(f->m_Plane)) { //if is it the case,check if the volume face intersect the face's plane if (f->IsIntersecting(m_Plane)) return (true); } }//i return (false); } ////////////////////////////////////////////////////////////////////////// void SBrushFace::FitTexture(int nX, int nY) { SBrushPoly *w; Vec3d mins,maxs; int i; float width, height; float rot_width, rot_height; float cosv,sinv,ang; float min_t, min_s, max_t, max_s; float s,t; Vec3d vecs[2]; Vec3d coords[4]; SMapTexInfo *td; if (nY < 1) nY = 1; if (nX < 1) nX = 1; mins=SetMaxBB(); maxs=SetMinBB(); td = &m_TexInfo; w = m_Poly; if (!w) return; w->CalcBounds(mins, maxs); ang = td->rotate / 180 * gf_PI; sinv = sinf(ang); cosv = cosf(ang); m_Plane.CalcTextureAxis(vecs[0], vecs[1], 1); min_s = mins | vecs[0]; min_t = mins | vecs[1]; max_s = maxs | vecs[0]; max_t = maxs | vecs[1]; width = max_s - min_s; height = max_t - min_t; coords[0][0] = min_s; coords[0][1] = min_t; coords[1][0] = max_s; coords[1][1] = min_t; coords[2][0] = min_s; coords[2][1] = max_t; coords[3][0] = max_s; coords[3][1] = max_t; min_s = min_t = 99999; max_s = max_t = -99999; for (i=0; i<4; i++) { s = cosv * coords[i][0] - sinv * coords[i][1]; t = sinv * coords[i][0] + cosv * coords[i][1]; if (i&1) { if (s > max_s) max_s = s; } else { if (s < min_s) min_s = s; if (i<2) { if (t < min_t) min_t = t; } else { if (t > max_t) max_t = t; } } } rot_width = (max_s - min_s); rot_height = (max_t - min_t); //@ASK Andrey. /* float temp; td->scale[0] = -(rot_width/((float)(gNE[m_shader->m_Id].m_Tex->m_Width*nX))); td->scale[1] = -(rot_height/((float)(gNE[m_shader->m_Id].m_Tex->m_Height*nY))); td->shift[0] = min_s/td->scale[0]; temp = (int)(td->shift[0] / (gNE[m_shader->m_Id].m_Tex->m_Width*nX)); temp = (temp+1)*gNE[m_shader->m_Id].m_Tex->m_Width*nX; td->shift[0] = (int)(temp - td->shift[0])%(gNE[m_shader->m_Id].m_Tex->m_Width*nX); td->shift[1] = min_t/td->scale[1]; temp = (int)(td->shift[1] / (gNE[m_shader->m_Id].m_Tex->m_Height*nY)); temp = (temp+1)*(gNE[m_shader->m_Id].m_Tex->m_Height*nY); td->shift[1] = (int)(temp - td->shift[1])%(gNE[m_shader->m_Id].m_Tex->m_Height*nY); */ }