/*==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 . 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(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;jgetSmGroup(); 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); }