You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
6.4 KiB
300 lines
6.4 KiB
14 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||
|
or by snail mail at:
|
||
|
Cyan Worlds, Inc.
|
||
|
14617 N Newport Hwy
|
||
|
Mead, WA 99021
|
||
|
|
||
|
*==LICENSE==*/
|
||
|
|
||
|
#include "hsTypes.h"
|
||
|
#include "Max.h"
|
||
|
|
||
|
#include "plRenderInstance.h"
|
||
|
|
||
|
class plNilView : public View
|
||
|
{
|
||
|
|
||
|
public:
|
||
|
|
||
|
Point2 ViewToScreen(Point3 p) { return Point2(p.x,p.y); }
|
||
|
|
||
|
plNilView()
|
||
|
{
|
||
|
projType = 1;
|
||
|
fov = hsScalarPI * 0.25f;
|
||
|
pixelSize = 1.f;
|
||
|
affineTM.IdentityMatrix();
|
||
|
worldToView.IdentityMatrix();
|
||
|
screenW=640.0f; screenH = 480.0f;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
static plNilView nilView;
|
||
|
|
||
|
plRenderInstance::plRenderInstance()
|
||
|
: fNext(nil),
|
||
|
fNode(nil),
|
||
|
fObject(nil),
|
||
|
fDeleteMesh(false)
|
||
|
{
|
||
|
mtl = nil;
|
||
|
mesh = nil;
|
||
|
flags = 0;
|
||
|
wireSize = 1.f;
|
||
|
vis = 1.f;
|
||
|
nodeID = 0;
|
||
|
objMotBlurFrame = 0;
|
||
|
objBlurID = 0;
|
||
|
objToWorld.IdentityMatrix();
|
||
|
objToCam.IdentityMatrix();
|
||
|
normalObjToCam.IdentityMatrix();
|
||
|
camToObj.IdentityMatrix();
|
||
|
obBox.Init();
|
||
|
center = Point3(0,0,0);
|
||
|
radsq = 0;
|
||
|
}
|
||
|
|
||
|
plRenderInstance::~plRenderInstance()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void plRenderInstance::Cleanup()
|
||
|
{
|
||
|
if( mesh && fDeleteMesh )
|
||
|
{
|
||
|
mesh->DeleteThis();
|
||
|
mesh = nil;
|
||
|
fDeleteMesh = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL plRenderInstance::Update(TimeValue& t)
|
||
|
{
|
||
|
fObject = fNode->EvalWorldState(t).obj;
|
||
|
if( !fObject )
|
||
|
return false;
|
||
|
|
||
|
// this shouldn't happen, we shouldn't be trying to make
|
||
|
// renderinstances from non GEOMOBJECT's
|
||
|
if( fObject->SuperClassID() != GEOMOBJECT_CLASS_ID )
|
||
|
return false;
|
||
|
|
||
|
if( mesh && fDeleteMesh )
|
||
|
{
|
||
|
mesh->DeleteThis();
|
||
|
mesh = nil;
|
||
|
}
|
||
|
fDeleteMesh = false;
|
||
|
mesh = ((GeomObject*)fObject)->GetRenderMesh(t, fNode, nilView, fDeleteMesh);
|
||
|
if( !mesh )
|
||
|
return false;
|
||
|
|
||
|
vis = fNode->GetVisibility(t);
|
||
|
if( vis < 0.0f )
|
||
|
{
|
||
|
vis = 0.0f;
|
||
|
SetFlag(INST_HIDE, 1);
|
||
|
return false;
|
||
|
}
|
||
|
if (vis > 1.0f) vis = 1.0f;
|
||
|
SetFlag(INST_HIDE, 0);
|
||
|
|
||
|
objMotBlurFrame = NO_MOTBLUR;
|
||
|
objBlurID = 0;
|
||
|
|
||
|
objToWorld = fNode->GetObjectTM(t);
|
||
|
objToCam = objToWorld;
|
||
|
camToObj = Inverse(objToCam);
|
||
|
|
||
|
normalObjToCam.IdentityMatrix();
|
||
|
Matrix3 inv = camToObj;
|
||
|
int i;
|
||
|
for( i = 0; i < 3; i++ )
|
||
|
normalObjToCam.SetRow(i, inv.GetColumn3(i));
|
||
|
|
||
|
obBox = mesh->getBoundingBox(nil);
|
||
|
center = obBox.Center();
|
||
|
radsq = LengthSquared(obBox.Width());
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
BOOL plRenderInstance::GetFromNode(INode* node, TimeValue& t, int idx)
|
||
|
{
|
||
|
fNext = nil;
|
||
|
|
||
|
fValid = Interval(t, t);
|
||
|
|
||
|
fNode = node;
|
||
|
mtl = node->GetMtl();
|
||
|
if( mtl )
|
||
|
{
|
||
|
wireSize = mtl->WireSize();
|
||
|
}
|
||
|
|
||
|
nodeID = idx;
|
||
|
|
||
|
ClearLights();
|
||
|
|
||
|
return Update(t);
|
||
|
}
|
||
|
|
||
|
BOOL plRenderInstance::CastsShadowsFrom(const ObjLightDesc& constLt)
|
||
|
{
|
||
|
ObjLightDesc& lt = const_cast<ObjLightDesc&>(constLt);
|
||
|
if( !fNode->CastShadows() )
|
||
|
return false;
|
||
|
|
||
|
if( !lt.ls.shadow )
|
||
|
return false;
|
||
|
|
||
|
if( lt.GetExclList() && lt.GetExclList()->TestFlag(NT_AFFECT_SHADOWCAST) )
|
||
|
{
|
||
|
int idx = lt.GetExclList()->FindNode(fNode);
|
||
|
BOOL isInc = lt.GetExclList()->TestFlag(NT_INCLUDE);
|
||
|
|
||
|
if( idx >= 0 )
|
||
|
{
|
||
|
return isInc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return !isInc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Point3 plRenderInstance::GetFaceNormal(int fnum)
|
||
|
{
|
||
|
Face* f = &mesh->faces[fnum];
|
||
|
Point3 a = GetCamVert(f->v[1]) - GetCamVert(f->v[0]);
|
||
|
Point3 b = GetCamVert(f->v[2]) - GetCamVert(f->v[0]);
|
||
|
|
||
|
Point3 n = CrossProd(a, b).Normalize();
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
Point3 plRenderInstance::GetFaceVertNormal(int fnum, int vertNum)
|
||
|
{
|
||
|
Point3 retNorm;
|
||
|
|
||
|
int smGroup=0;
|
||
|
|
||
|
Face* f = &mesh->faces[fnum];
|
||
|
|
||
|
// Get the rendered vertex. Don't use the device position, fPos.
|
||
|
RVertex &rv = mesh->getRVert(f->v[vertNum]);
|
||
|
|
||
|
// Number of normals at the vertex
|
||
|
int numNormalsAtVert = (rv.rFlags & NORCT_MASK);
|
||
|
|
||
|
// Specified normal ?
|
||
|
int specNrml = (rv.rFlags & SPECIFIED_NORMAL);
|
||
|
|
||
|
if (specNrml || (numNormalsAtVert == 1))
|
||
|
{
|
||
|
// The normal case is one normal per vertex (a vertex not beng shared by more than one smoothing group)
|
||
|
// We'll assign vertex normals here.
|
||
|
// If the object is faceted, this will be the same as the face normal.
|
||
|
retNorm = rv.rn.getNormal();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int found = 0;
|
||
|
for(int j=0;j<numNormalsAtVert; j++)
|
||
|
{
|
||
|
smGroup = rv.ern[j].getSmGroup();
|
||
|
// Since this vertex is shared by more than one smoothing group, it has multiple normals.
|
||
|
// This is fairly rare and doesn't occur in faceted objects.
|
||
|
// Just pick the first normal and use that as the vertex normal.
|
||
|
int faceSmGroup = f->getSmGroup();
|
||
|
if ((smGroup & faceSmGroup) == faceSmGroup)
|
||
|
{
|
||
|
retNorm = rv.ern[j].getNormal();
|
||
|
found++;
|
||
|
|
||
|
// NOTE: Remove this to really check smoothing groups
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
retNorm = retNorm * normalObjToCam;
|
||
|
retNorm.Normalize();
|
||
|
return retNorm;
|
||
|
}
|
||
|
|
||
|
Point3 plRenderInstance::GetCamVert(int vertnum)
|
||
|
{
|
||
|
return objToCam*mesh->verts[vertnum];
|
||
|
}
|
||
|
|
||
|
void plRenderInstance::GetObjVerts(int fnum, Point3 obp[3])
|
||
|
{
|
||
|
Face* f = &mesh->faces[fnum];
|
||
|
obp[0] = mesh->verts[f->v[0]];
|
||
|
obp[1] = mesh->verts[f->v[1]];
|
||
|
obp[2] = mesh->verts[f->v[2]];
|
||
|
}
|
||
|
|
||
|
void plRenderInstance::GetCamVerts(int fnum, Point3 cp[3])
|
||
|
{
|
||
|
Face* f = &mesh->faces[fnum];
|
||
|
cp[0] = objToCam*mesh->verts[f->v[0]];
|
||
|
cp[1] = objToCam*mesh->verts[f->v[1]];
|
||
|
cp[2] = objToCam*mesh->verts[f->v[2]];
|
||
|
}
|
||
|
|
||
|
Mtl* plRenderInstance::GetMtl(int fnum)
|
||
|
{
|
||
|
if( !mtl )
|
||
|
return nil;
|
||
|
|
||
|
if( TestFlag(INST_MTL_BYFACE) )
|
||
|
{
|
||
|
if( mtl->ClassID() != Class_ID(MULTI_CLASS_ID,0) )
|
||
|
return mtl;
|
||
|
|
||
|
Face* f = &mesh->faces[fnum];
|
||
|
int matIndex = f->getMatID();
|
||
|
return mtl->GetSubMtl(matIndex);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return mtl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG plRenderInstance::MtlRequirements(int mtlNum, int faceNum)
|
||
|
{
|
||
|
if( !mtl )
|
||
|
return 0;
|
||
|
|
||
|
if( TestFlag(INST_MTL_BYFACE) )
|
||
|
{
|
||
|
Mtl* faceMtl = GetMtl(faceNum);
|
||
|
return faceMtl ? faceMtl->Requirements(mtlNum) : 0;
|
||
|
}
|
||
|
return mtl->Requirements(mtlNum);
|
||
|
}
|