Files
FC1/Editor/Brush/BrushFace.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

721 lines
15 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// 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 <CREPolyMesh.h>
// 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;k<nNumVertices;k++)
{
SBrushVert vOrigVert=m_Poly->m_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;k<nNumVertices;k++)
{
SBrushVert vOrigVert=m_Poly->m_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; n<p->m_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; i<numPts-2; i++, vrtind+=3)
{
vrtind[0] = 0;
vrtind[1] = i+1;
vrtind[2] = i+2;
}
}
}
//Timur[9/16/2002]
/*
if (m_shader && m_shader->m_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; n<p->m_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;k<m_Poly->m_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; i<Vol->m_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);
*/
}