/*==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 .
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
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 "HeadSpin.h"
#include "plRealTimeLightBase.h"
#include "iparamm2.h"
#include "resource.h"
#include "decomp.h"
#include "hsv.h"
#include "target.h"
#include "MaxPlasmaMtls/Layers/plLayerTex.h"
#include "MaxPlasmaMtls/Layers/plLayerTexBitmapPB.h"
static int GetTargetPoint(TimeValue t, INode *inode, Point3& p)
{
Matrix3 tmat;
if (inode->GetTargetTM(t,tmat))
{
p = tmat.GetTrans();
return 1;
}
else
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//// plBaseLightProc Functions ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This class provides the base functionality for all the dialog procs for
// the ParamBlock rollouts for each light
void plBaseLightProc::ILoadComboBox( HWND hComboBox, const char *names[] )
{
SendMessage(hComboBox, CB_RESETCONTENT, 0, 0);
for (int i = 0; names[i]; i++)
SendMessage(hComboBox, CB_ADDSTRING, 0, (LPARAM)names[i]);
SendMessage(hComboBox, CB_SETCURSEL, 0, 0);
}
void plBaseLightProc::IBuildLightMesh( plRTLightBase *base, float coneSize )
{
base->BuildSpotMesh( coneSize );
base->fMesh = base->spotMesh;
}
BOOL plBaseLightProc::DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
IParamBlock2 *pb = map->GetParamBlock();
plRTLightBase *gl = (plRTLightBase *) pb->GetOwner();
switch( msg )
{
case WM_INITDIALOG:
{
HWND DecayTypeCombo = GetDlgItem(hWnd, IDC_LIGHT_DECAY);
HWND ShadowStateCombo = GetDlgItem(hWnd, IDC_SHADOW_TYPE);
map->Invalidate(plRTLightBase::kProjMapTexButton);
}
break;
case WM_COMMAND:
break;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
//// plLightTexPBAccessor Class Functions /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
plLightTexPBAccessor plLightTexPBAccessor::fAccessor;
void plLightTexPBAccessor::Set( PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t )
{
plRTLightBase* Obj = (plRTLightBase*)owner;
IParamBlock2 *pb = Obj->fLightPB;
switch (id)
{
case plRTLightBase::kProjMapTexButton:
if (1) //(val.bm)->bm)
{
if (pb->GetMap())
pb->GetMap()->Invalidate(plRTLightBase::kProjMapTexButton);
//pb->SetValue(plRTLightBase::kProjMapTexButton, Obj->fIP->GetTime(), val.bm);
PBBitmap* ThisMap = val.bm;
Obj->SetProjMap(&ThisMap->bi);
break;
}
default:
break;
}
}
void plLightTexPBAccessor::Get( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid )
{
}
////////////////////////////////////////////////////////////
//
// Mouse creation callback class for this plug-in
class RTLightMouseCallBack : public CreateMouseCallBack
{
plRTLightBase *ob;
public:
int proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3 &mat);
void SetObj(plRTLightBase *obj) { ob = obj; }
};
static RTLightMouseCallBack gRTMouseCallback;
int RTLightMouseCallBack::proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3 &mat)
{
switch (msg)
{
case MOUSE_POINT:
case MOUSE_MOVE:
switch (point)
{
case 0:
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
break;
case 1:
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
if (msg == MOUSE_POINT)
return 0;
break;
}
break;
case MOUSE_ABORT:
return CREATE_ABORT;
}
return CREATE_CONTINUE;
}
static RTLightMouseCallBack sRTBaseLgtCreateCB;
CreateMouseCallBack* plRTLightBase::GetCreateMouseCallBack()
{
sRTBaseLgtCreateCB.SetObj(this);
return &sRTBaseLgtCreateCB;
}
/////////////////////////////////////////////////////////////////////////////
#if 0
plRTLightBase::plRTLightBase() : fIP(nil), fClassDesc(nil), fLightPB(nil)
{
fColor = Color(0.5f, 0.5f, 1.f);
}
#endif
void plRTLightBase::SetHSVColor(TimeValue t, Point3 &hsv)
{
DWORD rgb = HSVtoRGB ((int)(hsv[0]*255.0f), (int)(hsv[1]*255.0f), (int)(hsv[2]*255.0f));
Point3 temp = fLightPB->GetPoint3(kLightColor, t);
Point3 rgbf;
rgbf[0] = temp.x / 255.0f;
rgbf[1] = temp.y / 255.0f;
rgbf[2] = temp.z / 255.0f;
SetRGBColor(t, rgbf);
}
Point3 plRTLightBase::GetHSVColor(TimeValue t, Interval& b)
{
int h, s, v;
Point3 rgbf = GetRGBColor(t, b);
DWORD rgb = RGB((int)(rgbf[0]*255.0f), (int)(rgbf[1]*255.0f), (int)(rgbf[2]*255.0f));
RGBtoHSV (rgb, &h, &s, &v);
return Point3(h/255.0f, s/255.0f, v/255.0f);
}
#define FZ (0.0f)
#define SET_QUAD(face, v0, v1, v2, v3) \
staticMesh[RT_OMNI +1].faces[face].setVerts(v0, v1, v2); \
staticMesh[RT_OMNI +1].faces[face].setEdgeVisFlags(1,1,0); \
staticMesh[RT_OMNI +1].faces[face+1].setVerts(v0, v2, v3); \
staticMesh[RT_OMNI +1].faces[face+1].setEdgeVisFlags(0,1,1);
void plRTLightBase::BuildStaticMeshes()
{
if(!meshBuilt) {
int nverts = 6;
int nfaces = 8;
// Build a leetle octahedron
staticMesh[RT_OMNI].setNumVerts(nverts);
staticMesh[RT_OMNI].setNumFaces(nfaces);
float s = 8.0f;
staticMesh[RT_OMNI].setVert(0, Point3( FZ,FZ, -s));
staticMesh[RT_OMNI].setVert(1, Point3( s, FZ, FZ));
staticMesh[RT_OMNI].setVert(2, Point3( FZ, s, FZ));
staticMesh[RT_OMNI].setVert(3, Point3(-s, FZ, FZ));
staticMesh[RT_OMNI].setVert(4, Point3( FZ,-s, FZ));
staticMesh[RT_OMNI].setVert(5, Point3( FZ,FZ, s));
staticMesh[RT_OMNI].faces[0].setVerts(0,1,4);
staticMesh[RT_OMNI].faces[1].setVerts(0,4,3);
staticMesh[RT_OMNI].faces[2].setVerts(0,3,2);
staticMesh[RT_OMNI].faces[3].setVerts(0,2,1);
staticMesh[RT_OMNI].faces[4].setVerts(5,1,2);
staticMesh[RT_OMNI].faces[5].setVerts(5,2,3);
staticMesh[RT_OMNI].faces[6].setVerts(5,3,4);
staticMesh[RT_OMNI].faces[7].setVerts(5,4,1);
for (int i=0; iID() )
return fLightPB;
else
return nil;
}
IParamBlock2 *plRTLightBase::GetParamBlock( int i )
{
switch( i )
{
case 0: return fLightPB;
default: return nil;
}
}
// So our animatables will show up in the trackview
int plRTLightBase::NumSubs()
{
return 1;
}
Animatable *plRTLightBase::SubAnim(int i)
{
return (Animatable *)fLightPB;
switch(i)
{
/* kRefProjMap,
kRefShadowProjMap,
kRefShadowType,
kRefOmniLight,
kRefSpotLight,
kRefTSpotLight,
kRefDirLight,
kRefTDirLight
*/
case kRefOmniLight:
case kRefSpotLight:
case kRefTSpotLight:
case kRefDirLight:
case kRefTDirLight:
case kRefProjDirLight:
return (Animatable*)fLightPB;
case kRefProjMap:
Texmap* MyMap;
return (Animatable*) fLightPB->GetValue(kProjMapTexButton, 0, MyMap, FOREVER);
case kRefShadowType:
return NULL;
default: return NULL;
}
//return (Animatable*) fLightPB;
}
TSTR plRTLightBase::SubAnimName(int i)
{
return fLightPB->GetLocalName();
switch(i)
{
case kRefOmniLight:return _T("");
case kRefSpotLight: return TSTR(GetString(IDS_DB_FSPOT));
case kRefTSpotLight:return _T("");
case kRefDirLight:return _T("");
case kRefTDirLight:return _T("");
case kRefProjMap: return TSTR(GetString(IDS_DS_PROJMAP));
case kRefShadowType: return _T("");
default: return _T("");
/* case PBLOCK_REF: return TSTR(GetString(IDS_RB_PARAMETERS));
case PROJMAP_REF: return TSTR(GetString(IDS_DS_PROJMAP));
case SHADPROJMAP_REF: return TSTR(GetString(IDS_DS_SHADPROJMAP));
case SHADTYPE_REF: return TSTR(GetString(IDS_DS_SHAD_GEN));
case EMITTER_REF:
if ( IsCompatibleRenderer ())
return TSTR(GetString(IDS_EMITTER));
else
return _T("");
default: return _T("");
*/
}
}
#if 0
RefTargetHandle plRTSpotLight::Clone(RemapDir &remap)
{
plRTLightBase *obj = TRACKED_NEW plRTSpotLight;
obj->GetParamBlock2->SetValue(kLightOn, t, fLightPB->GetInt(kLightOn, t));
// obj->fLightPB->SetValue(kLightType, t, fLightPB->GetInt(kLightType, t));
obj->fLightPB->SetValue(kLightColor, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kCastShadows, t, fLightPB->GetInt(kLightOn, t));
//obj->fLightPB->SetValue(kContrast, t, fLightPB->GetInt(kLightOn, t));
//obj->fLightPB->SetValue(kDiffSoft, t, fLightPB->GetInt(kLightOn, t));
//obj->fLightPB->SetValue(kDiffOn, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kSpec, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kSpecularColorSwatch, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kIntensity, t, fLightPB->GetInt(kLightOn, t));
if( IHasAttenuation() )
{
obj->fLightPB->SetValue(kUseAttenuationBool, t, fLightPB->GetInt(kLightType, t));
obj->fLightPB->SetValue(kAttenMaxFalloffEdit, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kAttenTypeRadio, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kShowConeBool, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kHotSpot, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kAttenMaxFalloffEdit, fLightPB->GetInt(kLightType, t));
obj->fLightPB->SetValue(kFallOff, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kUseProjectorBool, t, fLightPB->GetInt(kLightOn, t));
obj->fLightPB->SetValue(kProjMapTexButton, t, fLightPB->GetInt(kLightOn, t));
}
obj->ReplaceReference(kRefSpotLight,fLightPB->Clone(remap));
/*
GeneralLight* newob = TRACKED_NEW GeneralLight(type);
newob->enable = enable;
newob->coneDisplay = coneDisplay;
newob->useLight = useLight;
newob->attenDisplay = attenDisplay;
newob->useAtten = useAtten;
newob->useAttenNear = useAttenNear;
newob->attenNearDisplay = attenNearDisplay;
newob->decayDisplay = decayDisplay;
newob->shape = shape;
newob->shadow = shadow;
newob->shadowType = shadowType;
newob->overshoot = overshoot;
newob->projector = projector;
newob->absMapBias = absMapBias;
newob->exclList = exclList;
newob->softenDiffuse = softenDiffuse;
newob->affectDiffuse = affectDiffuse;
newob->affectSpecular = affectSpecular;
newob->ambientOnly = ambientOnly;
newob->decayType = decayType;
newob->atmosShadows = atmosShadows;
newob->atmosOpacity = atmosOpacity;
newob->atmosColAmt = atmosColAmt;
newob->ReplaceReference(PBLOCK_REF,pblock->Clone(remap));
if (projMap) newob->ReplaceReference(PROJMAP_REF,projMap->Clone(remap));
if (shadProjMap) newob->ReplaceReference(SHADPROJMAP_REF,shadProjMap->Clone(remap));
if (shadType) newob->ReplaceReference(SHADTYPE_REF,shadType->Clone(remap));
if (emitter) newob->ReplaceReference(EMITTER_REF ,emitter->Clone(remap));
BaseClone(this, newob, remap);
return(newob);
*/
//plRTLightBase *obj = (plRTLightBase*) fClassDesc->Create(false);
//obj->ReplaceReference(kRefComp, fLightPB->Clone(remap));
return obj;
}
#endif
void plRTLightBase::FreeCaches()
{
// fMesh.FreeAll();
}
void plRTLightBase::BoxCircle(TimeValue t, float r, float d, Box3& box, int extraPt, Matrix3 *tm)
{
Point3 q[3*NUM_CIRC_PTS];
int npts;
float asp;
if ( 1 /*Circle Object*/) { npts = NUM_CIRC_PTS+extraPt; asp = -1.0f; }
else { npts = 4+extraPt; asp = -1.0; }
GetConePoints(t, asp , r, d, q);
box.IncludePoints(q,npts,tm);
}
void plRTLightBase::BoxDirPoints(TimeValue t, float angle, float dist, Box3 &box, Matrix3 *tm)
{
int npts;
Point3 q[3*NUM_CIRC_PTS];
npts = 1 /*Circle Object*/? GetCirXPoints(t,angle,dist,q): GetRectXPoints(t,angle,dist,q);
box.IncludePoints(q,npts,tm);
}
void plRTLightBase::BoxPoints(TimeValue t, float angle, float dist, Box3 &box, Matrix3 *tm)
{
if (IsDir())
BoxCircle(t, angle, dist, box, 0,tm);
else
BoxDirPoints(t, angle, dist, box, tm);
}
void plRTLightBase::BoxLight(TimeValue t, INode *inode, Box3& box, Matrix3 *tm)
{
Point3 pt;
float d;
if (GetTargetPoint(t, inode, pt))
{
Point3 loc = inode->GetObjectTM(t).GetTrans();
d = FLength(loc - pt) / FLength(inode->GetObjectTM(t).GetRow(2));
box += tm? (*tm)*Point3(0.0f, 0.0f, -d): Point3(0.0f, 0.0f, -d);
}
else
{
d = GetTDist(t);
// if(fLightPB->GetInt(kLightType) == RT_FREE_DIR)
// d = GetFallsize(t);
if(IsSpot())
box += tm? (*tm)*Point3(0.0f, 0.0f, -d): Point3(0.0f, 0.0f, -d);
if(IsDir())
{
d = GetFallsize(t);
box += tm? (*tm)*Point3(0.0f, 0.0f, -d): Point3(0.0f, 0.0f, -d);
}
}
if( this->ClassID() == RTSPOT_LIGHT_CLASSID )
// if (fLightPB->GetInt(kLightType) == RT_FREE_SPOT || fLightPB->GetInt(kLightType) == RT_TARGET_SPOT)
if((fLightPB->GetInt(kShowConeBool,t)) || (extDispFlags & EXT_DISP_ONLY_SELECTED))
{
float rad = MaxF(GetHotspot(t), GetFallsize(t));
if (IsDir())
BoxCircle(t,rad,0.0f,box,1,tm);
BoxCircle(t,rad,d,box,1,tm);
}
if( this->ClassID() == RTDIR_LIGHT_CLASSID
|| this->ClassID() == RTPDIR_LIGHT_CLASSID )
// if (fLightPB->GetInt(kLightType) == RT_FREE_DIR || fLightPB->GetInt(kLightType) == RT_TARGET_DIR)
if((extDispFlags & EXT_DISP_ONLY_SELECTED))
{
float rad = MaxF(GetHotspot(t), GetFallsize(t));
if (IsDir())
BoxCircle(t,rad,0.0f,box,1,tm);
BoxCircle(t,rad,2.82841*GetFallsize(t),box,1,tm); //hack, hack. Do 2root2 at corners...
}
BOOL dispAtten = false;
BOOL dispAttenNear = false;
BOOL dispDecay = false;
if( this->ClassID() == RTOMNI_LIGHT_CLASSID || this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
dispAtten = fLightPB->GetInt(kUseAttenuationBool,t);
dispAttenNear = 0; //attenNearDisplay;
dispDecay = (GetDecayType()&&(extDispFlags & EXT_DISP_ONLY_SELECTED));
}
if( dispAtten || dispDecay)
{
if( this->ClassID() == RTOMNI_LIGHT_CLASSID )
{
Point3 q[3*NUM_CIRC_PTS];
float rad = 0;
if (dispAtten)
rad = MaxF(GetAtten(t, ATTEN_START), GetAtten(t, ATTEN_END));
if (dispDecay) rad = MaxF(rad,0.0/*GetDecayRadius(t)*/);
GetAttenPoints(t, rad, q);
box.IncludePoints(q,3*NUM_CIRC_PTS,tm);
}
if( this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
if (dispAtten)
{
BoxPoints(t, GetFallsize(t), GetAtten(t,ATTEN_END), box, tm);
BoxPoints(t, GetFallsize(t), GetAtten(t,ATTEN_START), box, tm);
}
if (dispDecay)
BoxPoints(t, GetFallsize(t), 0.0/*GetDecayRadius(t)*/, box, tm);
}
}
}
int plRTLightBase::GetRectXPoints(TimeValue t, float angle, float dist, Point3 *q)
{
int i;
if(dist==0.0f) dist = .00001f;
float ang = DegToRad(angle)/2.0f;
float da,sn,cs,x,y,z,a;
float aspect = GetAspect(t);
float w = dist * (float)tan(ang) * (float)sqrt((double)aspect);
float h = w/aspect;
float wang = (float)atan(w/dist);
float hang = (float)atan(h/dist);
float aw = float(atan(w/dist)*cos(hang)); // half-angle of top and bottom arcs
float ah = float(atan(h/dist)*cos(wang)); // half-angle of left and right arcs
int j = 0;
// draw horizontal and vertical center lines
da = wang/float(NUM_HALF_ARC);
for(i = -NUM_HALF_ARC, a = -wang; i<= NUM_HALF_ARC; i++, a+=da)
q[j++] = Point3(dist*(float)sin(a), 0.0f, -dist*(float)cos(a));
da = hang/float(NUM_HALF_ARC);
for(i = -NUM_HALF_ARC, a = -hang; i<= NUM_HALF_ARC; i++, a+=da)
q[j++] = Point3(0.0f, dist*(float)sin(a), -dist*(float)cos(a));
// draw top and bottom arcs
da = aw/float(NUM_HALF_ARC);
sn = (float)sin(hang);
cs = (float)cos(hang);
for (i = -NUM_HALF_ARC, a = -aw; i<= NUM_HALF_ARC; i++, a+=da)
{
x = dist*(float)sin(a);
z = -dist*(float)cos(a);
q[j] = Point3(x, z*sn, z*cs);
q[j+NUM_ARC_PTS] = Point3(x,-z*sn, z*cs);
j++;
}
j+= NUM_ARC_PTS;
// draw left and right arcs
da = ah/float(NUM_HALF_ARC);
sn = (float)sin(wang);
cs = (float)cos(wang);
for (i = -NUM_HALF_ARC, a = -ah; i<= NUM_HALF_ARC; i++, a+=da)
{
y = dist*(float)sin(a);
z = -dist*(float)cos(a);
q[j] = Point3( z*sn, y, z*cs);
q[j+NUM_ARC_PTS] = Point3(-z*sn, y, z*cs);
j++;
}
return 6*NUM_ARC_PTS;
}
int plRTLightBase::GetCirXPoints(TimeValue t, float angle, float dist, Point3 *q)
{
int i;
float ang = DegToRad(angle)/2.0f;
float da = ang/float(NUM_HALF_ARC);
// first draw circle:
float d = dist*(float)cos(ang);
GetConePoints(t, -1.0f, angle, d, q);
int j=NUM_CIRC_PTS;
// then draw Arc X
float a = -ang;
for(i = -NUM_HALF_ARC; i<= NUM_HALF_ARC; i++, a+=da)
q[j++] = Point3(0.0f, dist*(float)sin(a), -dist*(float)cos(a));
a = -ang;
for(i = -NUM_HALF_ARC; i<= NUM_HALF_ARC; i++, a+=da)
q[j++] = Point3(dist*(float)sin(a), 0.0f, -dist*(float)cos(a));
return NUM_CIRC_PTS + 2*NUM_ARC_PTS;
}
void plRTLightBase::DrawX(TimeValue t, float asp, int npts, float dist, GraphicsWindow *gw, int indx)
{
Point3 q[3*NUM_CIRC_PTS+1];
Point3 u[2];
GetConePoints(t, asp, GetFallsize(t), dist, q);
gw->polyline(npts, q,NULL, NULL, TRUE, NULL);
u[0] = q[0]; u[1] = q[2*indx];
gw->polyline(2, u,NULL, NULL, FALSE, NULL);
u[0] = q[indx]; u[1] = q[3*indx];
gw->polyline(2, u,NULL, NULL, FALSE, NULL);
}
void plRTLightBase::GetAttenPoints(TimeValue t, float rad, Point3 *q)
{
double a;
float sn, cs;
for(int i = 0; i < NUM_CIRC_PTS; i++)
{
a = (double)i * 2.0 * 3.1415926 / (double)NUM_CIRC_PTS;
sn = rad * (float)sin(a);
cs = rad * (float)cos(a);
q[i+0*NUM_CIRC_PTS] = Point3(sn, cs, 0.0f);
q[i+1*NUM_CIRC_PTS] = Point3(sn, 0.0f, cs);
q[i+2*NUM_CIRC_PTS] = Point3(0.0f, sn, cs);
}
}
// Draw warped rectangle
void plRTLightBase::DrawWarpRect(TimeValue t, GraphicsWindow *gw, float angle, float dist, Point3 *q)
{
GetRectXPoints(t, angle,dist,q);
for (int i=0; i<6; i++)
gw->polyline(NUM_ARC_PTS, q+i*NUM_ARC_PTS,NULL, NULL, FALSE, NULL);
}
void plRTLightBase::DrawCircleX(TimeValue t, GraphicsWindow *gw, float angle, float dist, Point3 *q)
{
GetCirXPoints(t, angle,dist,q);
gw->polyline(NUM_CIRC_PTS, q,NULL, NULL, TRUE, NULL); // circle
gw->polyline(NUM_ARC_PTS, q+NUM_CIRC_PTS,NULL, NULL, FALSE, NULL); // vert arc
gw->polyline(NUM_ARC_PTS, q+NUM_CIRC_PTS+NUM_ARC_PTS,NULL, NULL, FALSE, NULL); // horiz arc
}
void plRTLightBase::DrawSphereArcs(TimeValue t, GraphicsWindow *gw, float r, Point3 *q)
{
GetAttenPoints(t, r, q);
gw->polyline(NUM_CIRC_PTS, q, NULL, NULL, TRUE, NULL);
gw->polyline(NUM_CIRC_PTS, q+NUM_CIRC_PTS, NULL, NULL, TRUE, NULL);
gw->polyline(NUM_CIRC_PTS, q+2*NUM_CIRC_PTS,NULL, NULL, TRUE, NULL);
}
//
void plRTLightBase::DrawAttenCirOrRect(TimeValue t, GraphicsWindow *gw, float dist, BOOL froze, int uicol)
{
if (!froze) gw->setColor( LINE_COLOR, GetUIColor(uicol));
if (IsDir())
{
int npts,indx;
float asp;
npts = NUM_CIRC_PTS; asp = -1.0f; indx = SEG_INDEX;
DrawX(t, asp, npts, dist, gw, indx);
}
else
{
Point3 q[3*NUM_CIRC_PTS+1];
if( this->ClassID() == RTOMNI_LIGHT_CLASSID )
DrawSphereArcs(t, gw, dist, q);
else
DrawCircleX(t, gw, GetFallsize(t),dist,q);
}
}
int plRTLightBase::DrawAtten(TimeValue t, INode *inode, GraphicsWindow *gw)
{
BOOL dispAtten = false;
BOOL dispDecay = false;
if( this->ClassID() == RTOMNI_LIGHT_CLASSID || this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
dispAtten = (fLightPB->GetInt(kUseAttenuationBool,t) && (extDispFlags & EXT_DISP_ONLY_SELECTED));
//BOOL dispAttenNear = (fLightPB->GetInt(kUseNearAtten) && (extDispFlags & EXT_DISP_ONLY_SELECTED))?TRUE:fLightPB->GetInt(kShowFarAttenRanges);
dispDecay = (GetDecayType() && (extDispFlags & EXT_DISP_ONLY_SELECTED));
}
if (dispAtten || dispDecay)
{
Matrix3 tm = inode->GetObjectTM(t);
gw->setTransform(tm);
BOOL froze = inode->IsFrozen() && !inode->Dependent();
if (dispAtten)
{
DrawAttenCirOrRect(t, gw, GetAtten(t,ATTEN_START), froze, COLOR_START_RANGE);
DrawAttenCirOrRect(t, gw, GetAtten(t,ATTEN_END), froze, COLOR_END_RANGE);
}
if (dispDecay)
{
DrawAttenCirOrRect(t, gw, 0.0 /*DecayRadius() Stuff here */, froze, COLOR_DECAY_RADIUS);
}
}
return 0;
}
void plRTLightBase::GetLocalBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box)
{
//BuildMeshes(t);
//box = fMesh.getBoundingBox();
// int nv;
// Matrix3 tm;
// GetMat(t, node,vpt,tm);
// Point3 loc = tm.GetTrans();
// nv = fMesh.getNumVerts();
// box.Init();
// if(!(extDispFlags & EXT_DISP_ZOOM_EXT))
// box.IncludePoints(fMesh.verts,nv,&tm);
// else
// box += loc;
// tm = node->GetObjectTM(t);
// BoxLight(t, node, box, &tm);
Point3 loc = node->GetObjectTM(t).GetTrans();
float scaleFactor = vpt->NonScalingObjectSize()*vpt->GetVPWorldWidth(loc) / 360.0f;
box = fMesh.getBoundingBox();
box.Scale(scaleFactor);
BoxLight(t, node, box, NULL);
}
/*
RefTargetHandle Clone(RemapDir &remap = NoRemap())
{
plRTLightBase* newOb = TRACKED_NEW plRTLightBase;
newOb->fLightPB->SetValue(kLightOn, 0, this->fLightPB->GetInt(kLightOn, 0));
newOb->fLightPB->SetValue(kLightColor, 0, this->fLightPB->GetValue(kLightColor, 0));
newOb->fLightPB->SetValue(kLightExclude, 0, this->fLightPB->GetValue(kLightExclude, 0));
newOb->fLightPB->SetValue(kRed, 0, this->fLightPB->GetInt(kRed, 0));
newOb->fLightPB->SetValue(kGreen, 0, this->fLightPB->GetInt(kGreen, 0));
newOb->fLightPB->SetValue(kBlue, 0, this->fLightPB->GetInt(kBlue, 0));
newOb->fLightPB->SetValue(kHue, 0, this->fLightPB->GetInt(kHue, 0));
newOb->fLightPB->SetValue(kSat, 0, this->fLightPB->GetInt(kSat, 0));
newOb->fLightPB->SetValue(kVal, 0, this->fLightPB->GetInt(kVal, 0));
newOb->fLightPB->SetValue(kIntensity, 0, this->fLightPB->GetFloat(kIntensity, 0));
newOb->fLightPB->SetValue(kContrast, 0, this->fLightPB->GetFloat(kContrast, 0));
newOb->fLightPB->SetValue(kDiffSoft, 0, this->fLightPB->GetFloat(kDiffSoft, 0));
newOb->fLightPB->SetValue(kDiffOn, 0, this->fLightPB->GetInt(kDiffOn, 0));
newOb->fLightPB->SetValue(kStartAttenNear, 0, this->fLightPB->GetFloat(kStartAttenNear, 0));
newOb->fLightPB->SetValue(kAmbiOnly, 0, this->fLightPB->GetInt(kAmbiOnly, 0));
newOb->fLightPB->SetValue(kEndAttenNear, 0, this->fLightPB->GetFloat(kEndAttenNear, 0));
newOb->fLightPB->SetValue(kUseNearAtten, 0, this->fLightPB->GetInt(kUseNearAtten, 0));
newOb->fLightPB->SetValue(kShowNearAttenRanges, 0, this->fLightPB->GetInt(kShowNearAttenRanges, 0));
newOb->fLightPB->SetValue(kStartAttenFar, 0, this->fLightPB->GetFloat(kStartAttenFar, 0));
newOb->fLightPB->SetValue(kEndAttenFar, 0, this->fLightPB->GetFloat(kEndAttenFar, 0));
newOb->fLightPB->SetValue(kUseFarAtten, 0, this->fLightPB->GetInt(kUseFarAtten, 0));
newOb->fLightPB->SetValue(kShowFarAttenRanges, 0, this->fLightPB->GetInt(kShowFarAttenRanges, 0));
newOb->fLightPB->SetValue(kLightDecay, 0, this->fLightPB->GetInt(kLightDecay, 0));
newOb->fLightPB->SetValue(kRed, 0, this->fLightPB->GetInt(kRed, 0));
newOb->fLightPB->SetValue(kGreen, 0, this->fLightPB->GetInt(kGreen, 0));
newOb->fLightPB->SetValue(kBlue, 0, this->fLightPB->GetInt(kBlue, 0));
newOb->fLightPB->SetValue(kHue, 0, this->fLightPB->GetInt(kHue, 0));
newOb->fLightPB->SetValue(kSat, 0, this->fLightPB->GetInt(kSat, 0));
newOb->fLightPB->SetValue(kVal, 0, this->fLightPB->GetInt(kVal, 0));
newOb->fLightPB->SetValue(kIntensity, 0, this->fLightPB->GetFloat(kIntensity, 0));
newOb->fLightPB->SetValue(kContrast, 0, this->fLightPB->GetFloat(kContrast, 0));
newOb->fLightPB->SetValue(kDiffSoft, 0, this->fLightPB->GetFloat(kDiffSoft, 0));
newOb->fLightPB->SetValue(kDiffOn, 0, this->fLightPB->GetInt(kDiffOn, 0));
newOb->fLightPB->SetValue(kStartAttenNear, 0, this->fLightPB->GetFloat(kStartAttenNear, 0));
newOb->fLightPB->SetValue(kAmbiOnly, 0, this->fLightPB->GetInt(kAmbiOnly, 0));
newOb->fLightPB->SetValue(kEndAttenNear, 0, this->fLightPB->GetFloat(kEndAttenNear, 0));
newOb->fLightPB->SetValue(kUseNearAtten, 0, this->fLightPB->GetInt(kUseNearAtten, 0));
newOb->fLightPB->SetValue(kShowNearAttenRanges, 0, this->fLightPB->GetInt(kShowNearAttenRanges, 0));
newOb->fLightPB->SetValue(kStartAttenFar, 0, this->fLightPB->GetFloat(kStartAttenFar, 0));
newOb->fLightPB->SetValue(kEndAttenFar, 0, this->fLightPB->GetFloat(kEndAttenFar, 0));
*/
/*
kLightType, //Inserted in v1
kLightOn, //Inserted in v1
kLightColor, //Inserted in v1
kLightExclude, //Inserted in v1
kRed, //Inserted in v1
kGreen, //Inserted in v1
kBlue, //Inserted in v1
kHue, //Inserted in v1
kSat, //Inserted in v1
kVal, //Inserted in v1
kIntensity, //Inserted in v1
kContrast, //Inserted in v1
kDiffSoft, //Inserted in v1
kDiffOn, //Inserted in v1
kSpec, //Inserted in v1
kAmbiOnly, //Inserted in v1
kStartAttenNear, //Inserted in v1
kEndAttenNear, //Inserted in v1
kUseNearAtten, //Inserted in v1
kShowNearAttenRanges,//Inserted in v1
kStartAttenFar, //Inserted in v1
kEndAttenFar, //Inserted in v1
kUseFarAtten, //Inserted in v1
kShowFarAttenRanges, //Inserted in v1
kLightDecay, //Inserted in v1
kDecayEdit, //Inserted in v1
kShowDecay, //Inserted in v1
kUseProjectBool, //Inserted in v1
kProjMapTexButton, //Inserted in v1
kShowConeBool, //Inserted in v1
kOvershootBool, //Inserted in v1
kHotSpot, //Inserted in v1
kFallOff, //Inserted in v1
kLightShapeRadio, //Inserted in v1
kAspect, //Inserted in v1
kUseProjectorBool, //Inserted in v1
kProjMapTexButton2, //Inserted in v1
kTargetDist //Inserted in v1
GeneralLight* newob = TRACKED_NEW GeneralLight(type);
newob->enable = enable;
newob->coneDisplay = coneDisplay;
newob->useLight = useLight;
newob->attenDisplay = attenDisplay;
newob->useAtten = useAtten;
newob->useAttenNear = useAttenNear;
newob->attenNearDisplay = attenNearDisplay;
newob->decayDisplay = decayDisplay;
newob->shape = shape;
newob->shadow = shadow;
newob->shadowType = shadowType;
newob->overshoot = overshoot;
newob->projector = projector;
newob->absMapBias = absMapBias;
newob->exclList = exclList;
newob->softenDiffuse = softenDiffuse;
newob->affectDiffuse = affectDiffuse;
newob->affectSpecular = affectSpecular;
newob->ambientOnly = ambientOnly;
newob->decayType = decayType;
newob->atmosShadows = atmosShadows;
newob->atmosOpacity = atmosOpacity;
newob->atmosColAmt = atmosColAmt;
newob->ReplaceReference(PBLOCK_REF,pblock->Clone(remap));
if (projMap) newob->ReplaceReference(PROJMAP_REF,projMap->Clone(remap));
if (shadProjMap) newob->ReplaceReference(SHADPROJMAP_REF,shadProjMap->Clone(remap));
if (shadType) newob->ReplaceReference(SHADTYPE_REF,shadType->Clone(remap));
if (emitter) newob->ReplaceReference(EMITTER_REF ,emitter->Clone(remap));
BaseClone(this, newob, remap);
return(newob);
}
*/
//}
void plRTLightBase::GetWorldBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box)
{
GetLocalBoundBox( t, node, vpt, box );
box = box * node->GetObjectTM( t );
}
void plRTLightBase::GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel )
{
box = fMesh.getBoundingBox(tm);
}
int plRTLightBase::Display(TimeValue t, INode *node, ViewExp *vpt, int flags)
{
Matrix3 m;
// if (!enable)
// return 0;
GraphicsWindow *gw = vpt->getGW();
GetMat(t,node,vpt,m);
gw->setTransform(m);
DWORD rlim = gw->getRndLimits();
gw->setRndLimits(GW_WIREFRAME|GW_BACKCULL|(gw->getRndMode() & GW_Z_BUFFER));
if (node->Selected())
gw->setColor( LINE_COLOR, GetSelColor());
else if(!node->IsFrozen() && !node->Dependent())
{
if(fLightPB->GetInt(kLightOn))
gw->setColor( LINE_COLOR, GetUIColor(COLOR_LIGHT_OBJ));
// I un-commented this line DS 6/11/99
else
gw->setColor( LINE_COLOR, 0.0f, 0.0f, 0.0f);
}
fMesh.render( gw, gw->getMaterial(),
(flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL);
DrawConeAndLine(t, node, gw, 1);
// DrawAtten(t, node, gw);
gw->setRndLimits(rlim);
return 0;
}
static void RemoveScaling(Matrix3 &tm)
{
AffineParts ap;
decomp_affine(tm, &ap);
tm.IdentityMatrix();
tm.SetRotate(ap.q);
tm.SetTrans(ap.t);
}
void plRTLightBase::GetMat(TimeValue t, INode* inode, ViewExp *vpt, Matrix3& tm)
{
tm = inode->GetObjectTM(t);
// tm.NoScale();
RemoveScaling(tm);
float scaleFactor = vpt->NonScalingObjectSize()*vpt->GetVPWorldWidth(tm.GetTrans())/(float)360.0;
tm.Scale(Point3(scaleFactor,scaleFactor,scaleFactor));
}
void plRTLightBase::GetConePoints(TimeValue t, float aspect, float angle, float dist, Point3 *q)
{
float ta = (float)tan(0.5*DegToRad(angle));
if(1 /*fLightPB->GetFloat(kAspect, t) <= 0.0f*/)
{
// CIRCULAR
float rad = dist * ta;
double a;
if(IsDir())
rad = angle;
int i;
for(i = 0; i < NUM_CIRC_PTS; i++) {
a = (double)i * 2.0 * 3.1415926 / (double)NUM_CIRC_PTS;
q[i] = Point3(rad*(float)sin(a), rad*(float)cos(a), -dist);
}
q[i] = q[0] + Point3(0.0f, 15.0f, 0.0f);
}
else
{
// RECTANGULAR
float w = IsDir()? angle : dist * ta * (float)sqrt((double)aspect);
float h = w / aspect;
q[0] = Point3( w, h,-dist);
q[1] = Point3(-w, h,-dist);
q[2] = Point3(-w,-h,-dist);
q[3] = Point3( w,-h,-dist);
q[4] = Point3( 0.0f, h+15.0f, -dist);
q[5] = Point3( 0.0f, h, -dist);
}
}
#define HOTCONE 0
#define FALLCONE 1
void plRTLightBase::DrawCone(TimeValue t, GraphicsWindow *gw, float dist)
{
Point3 q[NUM_CIRC_PTS+1], u[3];
int dirLight = IsDir();
int i;
BOOL dispAtten = false;
BOOL dispDecay = false;
if( this->ClassID() == RTOMNI_LIGHT_CLASSID || this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
dispAtten = (fLightPB->GetInt(kUseAttenuationBool, t) && (extDispFlags & EXT_DISP_ONLY_SELECTED));//attenDisplay;
dispDecay = (/*fLightPB->GetInt(kAttenTypeRadio, t)*/GetDecayType() && (extDispFlags & EXT_DISP_ONLY_SELECTED));
}
if(!IsDir())
GetConePoints(t, -1.0f, GetHotspot(t), dist, q);
else
GetConePoints(t, -1.0f, 20.0, dist, q);
gw->setColor( LINE_COLOR, GetUIColor(COLOR_HOTSPOT));
if(1 /*Circular Hack*/) {
// CIRCULAR
if(GetHotspot(t) >= GetFallsize(t))
{
// draw (far) hotspot circle
u[0] = q[0];
u[1] = q[NUM_CIRC_PTS];
gw->polyline( 2, u, NULL, NULL, FALSE, NULL);
}
gw->polyline(NUM_CIRC_PTS, q, NULL, NULL, TRUE, NULL);
if (dirLight)
{
// draw 4 axial hotspot lines
for (i = 0; i < NUM_CIRC_PTS; i += SEG_INDEX)
{
u[0] = q[i]; u[1] = q[i]; u[1].z += dist;
gw->polyline( 2, u, NULL, NULL, FALSE, NULL );
}
GetConePoints(t, -1.0f, 20/*GetHotspot(t)*/, 0.0f, q);
// draw (near) hotspot circle
gw->polyline(NUM_CIRC_PTS, q, NULL, NULL, TRUE, NULL);
}
else
{
// draw 4 axial lines
u[0] = Point3(0,0,0);
for (i = 0; i < NUM_CIRC_PTS; i += SEG_INDEX)
{
u[1] = q[i];
gw->polyline( 2, u, NULL, NULL, FALSE, NULL );
}
}
if(!IsDir())
GetConePoints(t, -1.0f, GetFallsize(t), dist, q);
else
GetConePoints(t, -1.0f, 200.0, dist, q);
gw->setColor( LINE_COLOR, GetUIColor(COLOR_FALLOFF));
if(GetHotspot(t) < GetFallsize(t))
{
// draw (far) fallsize circle
u[0] = q[0]; u[1] = q[NUM_CIRC_PTS];
gw->polyline( 2, u, NULL, NULL, FALSE, NULL);
u[0] = Point3(0,0,0);
}
gw->polyline(NUM_CIRC_PTS, q, NULL, NULL, TRUE, NULL);
if (dirLight)
{
float dfar = q[0].z;
float dnear = 0.0f;
if (dispAtten)
{
dfar = MinF(-GetAtten(t,ATTEN_END),dfar);
/// dnear = MaxF(-GetAtten(t,ATTEN_START),dnear);
}
if (dispDecay) {
dfar = MinF(/*-GetDecayRadius(t)*/ 0.0,dfar);
}
// draw axial fallsize lines
for (i = 0; i < NUM_CIRC_PTS; i += SEG_INDEX)
{
u[0] = q[i]; u[0].z = dfar; u[1] = q[i]; u[1].z = dnear;
gw->polyline( 2, u, NULL, NULL, FALSE, NULL );
}
GetConePoints(t, -1.0f, 10000.0, 0.0f, q);
// draw (near) fallsize circle
gw->polyline(NUM_CIRC_PTS, q, NULL, NULL, TRUE, NULL);
}
else
{
float cs = (float)cos(DegToRad(GetFallsize(t)*0.5f));
float dfar = q[0].z;
if (dispAtten)
dfar = MinF(-cs*GetAtten(t,ATTEN_END),dfar);
if (dispDecay)
dfar = MinF(/*-cs*GetDecayRadius(t)*/0.0,dfar);
for (i = 0; i < NUM_CIRC_PTS; i += SEG_INDEX)
{
u[1] = -q[i]*dfar/dist;
gw->polyline( 2, u, NULL, NULL, FALSE, NULL );
}
}
}
}
int plRTLightBase::DrawConeAndLine(TimeValue t, INode* inode, GraphicsWindow *gw, int drawing )
{
if(!IsSpot() && !IsDir())
return 0;
Matrix3 tm = inode->GetObjectTM(t);
gw->setTransform(tm);
gw->clearHitCode();
if( 0 )
{
Point3 pt,v[3];
if (GetTargetPoint(t, inode, pt))
{
float den = FLength(tm.GetRow(2));
float dist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f;
fLightPB->SetValue(kAttenMaxFalloffEdit, t, dist);
//fLightPB->SetValue(kTargetDist, t, dist);
//if (hSpotLight&&(currentEditLight==this)) {
// TCHAR buf[40];
// _stprintf(buf,_T("%0.3f"),targDist);
// SetWindowText(GetDlgItem(hSpotLight,IDC_TARG_DISTANCE),buf);
// }
if ((drawing != -1) && (fLightPB->GetInt(kShowConeBool, t) || (extDispFlags & EXT_DISP_ONLY_SELECTED)))
DrawCone(t, gw, dist);
if(!inode->IsFrozen() && !inode->Dependent())
gw->setColor( LINE_COLOR, GetUIColor(COLOR_TARGET_LINE));
v[0] = Point3(0,0,0);
v[1] = Point3(0.0f, 0.0f, (drawing == -1)? (-0.9f * dist): -dist);
gw->polyline( 2, v, NULL, NULL, FALSE, NULL );
}
}
else if( this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
if ((drawing != -1) && (fLightPB->GetInt(kShowConeBool, t) || (extDispFlags & EXT_DISP_ONLY_SELECTED)))
DrawCone(t, gw, fLightPB->GetFloat( kAttenMaxFalloffEdit, t ) );
}
else if( this->ClassID() == RTDIR_LIGHT_CLASSID )
{
if ((extDispFlags & EXT_DISP_ONLY_SELECTED))
DrawCone(t, gw, 500/*GetTDist(t)*/);
}
return gw->checkHitCode();
}
//// DrawArrow ///////////////////////////////////////////////////////////////
void plRTLightBase::DrawArrow( TimeValue t, GraphicsWindow *gw, Point3 &direction, float dist )
{
Point3 pts[ 5 ];
pts[ 0 ] = Point3( 0, 0, 0 );
pts[ 1 ] = direction * dist;
pts[ 3 ] = pts[ 1 ] - direction * 10.f;
pts[ 2 ] = pts[ 3 ] + Point3( direction.y, direction.z, direction.x ) * 5.f;
gw->polyline( 4, pts, nil, nil, true, nil );
}
int plRTLightBase::HitTest(TimeValue t, INode *node, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt)
{
DWORD savedLimits;
GraphicsWindow *gw = vpt->getGW();
HitRegion hitRegion;
int res;
Matrix3 m;
MakeHitRegion(hitRegion, type, crossing, 4, p);
Material *mtl = gw->getMaterial();
gw->setRndLimits( ((savedLimits = gw->getRndLimits()) | GW_PICK) & ~(GW_ILLUM|GW_BACKCULL));
GetMat(t,node,vpt,m);
//BuildMeshes(t);
gw->setTransform(m);
res = fMesh.select( gw, mtl, &hitRegion, flags & HIT_ABORTONHIT);
// if not, check the target line, and set the pair flag if it's hit
if( !res )
{
// this special case only works with point selection of targeted lights
if((type != HITTYPE_POINT) || !node->GetTarget())
return 0;
// don't let line be active if only looking at selected stuff and target isn't selected
if((flags & HIT_SELONLY) && !node->GetTarget()->Selected() )
return 0;
gw->clearHitCode();
if(res = DrawConeAndLine(t, node, gw, -1))
node->SetTargetNodePair(1);
}
gw->setRndLimits(savedLimits);
return res;
//return fMesh.select(gw,node->Mtls(),&hitRegion,flags & HIT_ABORTONHIT,node->NumMtls());
}
static void GenericSnap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt)
{
// Make sure the vertex priority is active and at least as important as the best snap so far
if(snap->vertPriority > 0 && snap->vertPriority <= snap->priority)
{
Matrix3 tm = inode->GetObjectTM(t);
GraphicsWindow *gw = vpt->getGW();
gw->setTransform(tm);
Point2 fp = Point2((float)p->x, (float)p->y);
IPoint3 screen3;
Point2 screen2;
Point3 vert(0.0f,0.0f,0.0f);
gw->wTransPoint(&vert,&screen3);
screen2.x = (float)screen3.x;
screen2.y = (float)screen3.y;
// Are we within the snap radius?
int len = (int)Length(screen2 - fp);
if(len <= snap->strength)
{
// Is this priority better than the best so far?
if(snap->vertPriority < snap->priority)
{
snap->priority = snap->vertPriority;
snap->bestWorld = vert * tm;
snap->bestScreen = screen2;
snap->bestDist = len;
}
// Closer than the best of this priority?
else if(len < snap->bestDist)
{
snap->priority = snap->vertPriority;
snap->bestWorld = vert * tm;
snap->bestScreen = screen2;
snap->bestDist = len;
}
}
}
}
void plRTLightBase::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt)
{
GenericSnap(t,inode,snap,p,vpt);
}
// This generic snap routine is used to snap to the 0,0,0 point of the given node. For lights,
// this works to snap all types.
RefTargetHandle plRTLightBase::GetReference(int i)
{
/*
kRefProjMap,
kRefShadowProjMap,
kRefShadowType,
*///Texmap* MyMap;
switch(i)
{
case kRefGeneralLightProp:
return NULL;
case kRefProjMap:
//if(fLightPB->GetTexmap(kProjMapTexButton, 0) != NULL)
//{
// MyMap = fLightPB->GetTexmap(kProjMapTexButton, 0);
//return (RefTargetHandle) MyMap;
//}else
return NULL;
case kRefShadowProjMap:
return NULL;
case kRefShadowType:
return NULL;
case kRefOmniLight:
case kRefSpotLight:
case kRefTSpotLight:
case kRefDirLight:
case kRefTDirLight:
case kRefProjDirLight:
return (RefTargetHandle)fLightPB;
default:
return NULL;
}
}
void plRTLightBase::SetReference(int ref, RefTargetHandle rtarg)
{
//Texmap* MyMap;
switch(ref)
{
case kRefGeneralLightProp:
return;
case kRefProjMap:
//MyMap = (Texmap *)rtarg;
//fLightPB->SetValue(kProjMapTexButton, 0, MyMap);
//if (projMapName)
// projMapName->SetText(projMap?projMap->GetFullName().data():GetString(IDS_DB_NONE));
return;
case kRefShadowProjMap:
return;
case kRefShadowType:
return;
case kRefOmniLight:
case kRefSpotLight:
case kRefTSpotLight:
case kRefDirLight:
case kRefTDirLight:
case kRefProjDirLight:
fLightPB = (IParamBlock2*)rtarg; break;
}
//fLightPB = (IParamBlock2*)rtarg;
}
RefResult plRTLightBase::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
if( fLightPB )
{
ParamID param = fLightPB->LastNotifyParamID();
if( param == kAmbientOnlyStub )
{
fLightPB->EnableNotifications( false );
fLightPB->SetValue( kAmbientOnlyStub, TimeValue( 0 ), false );
// Assume this was true, since, well, we're IN NotifyRefChanged....
fLightPB->EnableNotifications( true );
return REF_SUCCEED;
}
}
return REF_SUCCEED;
}
void plRTLightBase::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev)
{
fIP = ip;
fClassDesc->BeginEditParams(ip, this, flags, prev);
}
void plRTLightBase::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next)
{
GenLight::EndEditParams( ip, flags, next );
fIP = NULL;
fClassDesc->EndEditParams(ip, this, flags, next);
}
RefResult plRTLightBase::EvalLightState(TimeValue t, Interval& valid, LightState *ls)
{
//t uselight;
//#if 0 //fLightPB->GetInt(kLightOn, t);
if(fLightPB->GetInt(kLightOn, t) == true)
ls->color = GetRGBColor(t,valid);
else
ls->color = Color(0,0,0);
ls->on = fLightPB->GetInt(kLightOn, t);
ls->intens = GetIntensity(t, valid);
if( this->ClassID() == RTSPOT_LIGHT_CLASSID || this->ClassID() == RTOMNI_LIGHT_CLASSID )
{
ls->hotsize = GetHotspot(t, valid);
ls->fallsize = GetFallsize(t, valid);
ls->useNearAtten = GetUseAttenNear();
ls->useAtten = GetUseAtten();
ls->attenStart = GetAtten(t, ATTEN_START, valid);
ls->attenEnd = GetAtten(t, ATTEN_END, valid);
}else
{
ls->hotsize = 20;
ls->fallsize = 10000;
ls->useNearAtten = false; //GetUseAttenNear();
ls->useAtten = false; //GetUseAtten();
//ls->attenStart = GetAtten(t, ATTEN_START, valid);
//ls->attenEnd = GetAtten(t, ATTEN_END, valid);
}
ls->shape = GW_SHAPE_CIRCULAR; //fLightPB->GetInt(kLightShapeRadio);
ls->aspect = -1.0;//GetAspect(t, valid);
ls->overshoot = false; //GetOvershoot();
ls->shadow = GetShadow();
ls->ambientOnly = false; //fLightPB->GetValue( kAmbiOnly,t, ls->ambientOnly, valid); //ls->ambientOnly = fLightP.AmbiOnly;
ls->affectDiffuse = true; //fLightPB->GetInt(kDiffOn,t); //ls->affectDiffusey = fLightP.AmbiOnly;
ls->affectSpecular = fLightPB->GetInt(kSpec,t); //ls- = fLightP.DiffOn;;
//ls->
if( this->ClassID() == RTOMNI_LIGHT_CLASSID )
ls->type = OMNI_LGT;
else if( this->ClassID() == RTDIR_LIGHT_CLASSID || this->ClassID() == RTPDIR_LIGHT_CLASSID )
ls->type = DIRECT_LGT;
else
ls->type = SPOT_LGT;
return REF_SUCCEED;
}
#if 0
#define PLASMAOBJ_DATA_CHUNK 1
IOResult plRTLightBase::Save(ISave* isave)
{
return IO_OK;
}
IOResult plRTLightBase::Load(ILoad* iload)
{
ULONG nb;
IOResult res;
int numrefs = 0;
while (IO_OK == (res = iload->OpenChunk()))
{
if (iload->CurChunkID() == PLASMAOBJ_DATA_CHUNK)
res = iload->Read(&numrefs, sizeof(int), &nb);
iload->CloseChunk();
if (res != IO_OK)
return res;
}
return IO_OK;
}
#endif
ObjLightDesc *plRTLightBase::CreateLightDesc(INode *n, BOOL forceShadowBuf)
{
return NULL;
}
void plRTLightBase::SetHotspot(TimeValue t, float f)
{
if(!IsSpot())
return;
if(f < 0.5f)
f = 0.5f;
if(!IsDir() && (f > 179.5f))
f = 179.5f;
//pblock->SetValue( PB_HOTSIZE, t, f );
fLightPB->SetValue(kHotSpot, t, f);
//fLightP.HotSpot = f;
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
float plRTLightBase::GetHotspot(TimeValue t, Interval& valid)
{
Interval iv;
if(!IsSpot() && !IsDir())
return -1.0f;
float f;
//pblock->GetValue( PB_HOTSIZE, t, f, valid );
if(IsSpot())
fLightPB->GetValue(kHotSpot, t, f, FOREVER);
else
f = 20.0;
if(GetFallsize(t, iv) < f )
return GetFallsize(t, iv) - 2.0;
return f;
}
void plRTLightBase::SetRGBColor(TimeValue t, Point3& rgb)
{
//fLightPB->SetValue(plRTLightBase::kRed, t, rgb.x);
//fLightPB->SetValue(plRTLightBase::kGreen, t, rgb.y);
//fLightPB->SetValue(plRTLightBase::kBlue, t, rgb.z);
fLightPB->SetValue(kLightColor, t, rgb );
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
Point3 plRTLightBase::GetRGBColor(TimeValue t, Interval &valid)
{
//Point3 Foo = Point3(fLightPB->GetInt(plRTLightBase::kRed, t), fLightPB->GetInt(plRTLightBase::kGreen, t), fLightPB->GetInt(plRTLightBase::kBlue, t));
Point3 rgb;
fLightPB->GetValue( kLightColor, t, rgb, valid );
return rgb;
}
void plRTLightBase::SetFallsize(TimeValue t, float f)
{
if(!IsSpot() )
return;
if(f < 0.5f)
f = 0.5f;
if(!IsDir() && (f > 179.5f))
f = 179.5f;
//pblock->SetValue( PB_FALLSIZE, t, f );
fLightPB->SetValue(kFallOff, t, f);
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
float plRTLightBase::GetFallsize(TimeValue t, Interval& valid)
{
if(!IsSpot() && !IsDir())
return -1.0f;
float f;
//pblock->GetValue( PB_FALLSIZE, t, f, valid );
if(IsSpot())
fLightPB->GetValue(kFallOff, t, f, valid);
else
f = 200.0;
return f;
}
void plRTLightBase::SetAtten(TimeValue t, int which, float f)
{
if(which != ATTEN_START)
fLightPB->SetValue(kAttenMaxFalloffEdit, t, f);
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
float plRTLightBase::GetAtten(TimeValue t, int which, Interval& valid)
{
float f = 0.0;
//if(fLightPB->GetInt(kEndAttenFar, t) == 1)
//if(LyteType == RT_OMNI)
// fLightPB->GetValue(kStartAttenFar, t, f, FOREVER);
//else
// fLightPB->GetValue(kStartAttenNear, t, f, FOREVER);
if(which == LIGHT_ATTEN_START)
return f;
else
return( fLightPB->GetFloat(kAttenMaxFalloffEdit, t));
//return f;
}
void plRTLightBase::SetTDist(TimeValue t, float f)
{
// int i;
// fLightPB->GetInt(kLightType, t, i);
//pblock->SetValue( PB_TDIST, t, f );
//To be implemented.
if( IHasAttenuation() )
fLightPB->SetValue(kAttenMaxFalloffEdit, t, f);
//fLightPB->SetValue(kTargetDist, t, f);
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
float plRTLightBase::GetTDist(TimeValue t, Interval& valid)
{
if(!IsSpot())
return -1.0f;
// int i;
//fLightPB->GetValue(kLightType, t, i, valid);
float f = -1.0;
fLightPB->GetFloat( kAttenMaxFalloffEdit, t );
//pblock->GetValue( PB_TDIST, t, f, valid );
//fLightPB->GetValue(kTargetDist, t, f, valid);
return f;
}
void plRTLightBase::SetConeDisplay(int s, int notify)
{
if(!IsDir())
fLightPB->SetValue(kShowConeBool, 0, s);
if(notify && IsSpot())
NotifyDependents(FOREVER, PART_OBJ, REFMSG_CHANGE);
}
BOOL plRTLightBase::GetConeDisplay(void)
{
if(!IsDir())
return fLightPB->GetInt(kShowConeBool);
return
false;
}
void plRTLightBase::SetProjMap(BitmapInfo* pmap)
{
//plLayerTex* MyMap = TRACKED_NEW plLayerTex;
if(!fTex)
fTex = TRACKED_NEW plLayerTex;
fTex->SetBitmap(pmap);
ReplaceReference(kRefProjMap,fTex);
IParamBlock2 *bitmapPB = fTex->GetParamBlockByID(plLayerTex::kBlkBitmap);
bitmapPB->SetValue(kBmpUseBitmap, 0, 1);
// This is set in the call to fTex->SetBitmap(pmap)
//PBBitmap pbb(*pmap);
//bitmapPB->SetValue(kBmpBitmap, 0, &pbb);
//Texmap* MyMap;
//fLightPB->GetValue(kProjMapTexButton, 0, MyMap, FOREVER);
if (fTex) fLightPB->SetValue(kUseProjectorBool, 0, true);
NotifyDependents(FOREVER,0,REFMSG_SUBANIM_STRUCTURE_CHANGED);
if( fLightPB->GetMap() )
{
fLightPB->GetMap()->Invalidate(kProjMapTexButton);
fLightPB->GetMap()->Invalidate(kUseProjectorBool);
}
}
BOOL plRTLightBase::GetShadow()
{
return fLightPB->GetInt(kCastShadows);
}
void plRTLightBase::SetShadow(int a)
{
fLightPB->SetValue(kCastShadows, 0, 1);
}
Texmap* plRTLightBase::GetProjMap()
{
if( !fLightPB->GetInt(kUseProjectorBool) )
return NULL;
if( GetTex() )
{
const char* dbgTexName = GetTex()->GetName();
IParamBlock2 *bitmapPB = fTex->GetParamBlockByID(plLayerTex::kBlkBitmap);
hsAssert(bitmapPB, "LayerTex with no param block");
int noCompress = fLightPB->GetInt(kProjNoCompress);
int noMip = fLightPB->GetInt(kProjNoMip);
bitmapPB->SetValue(kBmpNonCompressed, TimeValue(0), noCompress);
bitmapPB->SetValue(kBmpNoFilter, TimeValue(0), noMip);
}
return (Texmap*) GetTex();
}
void plRTLightBase::UpdateTargDistance(TimeValue t, INode* inode)
{
if( this->ClassID() == RTSPOT_LIGHT_CLASSID )
{
Point3 pt,v[3];
if (GetTargetPoint(t, inode, pt))
{
Matrix3 tm = inode->GetObjectTM(t);
float den = FLength(tm.GetRow(2));
float dist = (den!=0) ? FLength(tm.GetTrans()-pt) / den : 0.0f;
fLightPB->SetValue(kAttenMaxFalloffEdit, t, dist);
// fLightPB->SetValue(kTargetDist, t, dist);
//TCHAR buf[40];
//_stprintf(buf,_T("%0.3f"),targDist);
//SetWindowText(GetDlgItem(hSpotLight,IDC_TARG_DISTANCE),buf);
}
}
}
///
//
//
// Target Creation for Targeted Lights...
//
//
//
#if 0
class TSpotCreationManager : public MouseCallBack, ReferenceMaker
{
private:
CreateMouseCallBack *createCB;
INode *lgtNode,*targNode;
plRTLightBase *lgtObject;
TargetObject *targObject;
int attachedToNode;
IObjCreate *createInterface;
ClassDesc *cDesc;
Matrix3 mat; // the nodes TM relative to the CP
IPoint2 pt0;
int ignoreSelectionChange;
int lastPutCount;
void CreateNewObject();
int NumRefs() { return 1; }
RefTargetHandle GetReference(int i) { return (RefTargetHandle)lgtNode; }
void SetReference(int i, RefTargetHandle rtarg) { lgtNode = (INode *)rtarg; }
// StdNotifyRefChanged calls this, which can change the partID to new value
// If it doesnt depend on the particular message& partID, it should return
// REF_DONTCARE
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
public:
void Begin( IObjCreate *ioc, ClassDesc *desc );
void End();
TSpotCreationManager() { ignoreSelectionChange = FALSE; }
int proc( HWND hwnd, int msg, int point, int flag, IPoint2 m );
BOOL SupportAutoGrid(){return TRUE;}
};
#define CID_TSPOTCREATE CID_USER + 3
class TSpotCreateMode : public CommandMode {
TSpotCreationManager proc;
public:
void Begin( IObjCreate *ioc, ClassDesc *desc ) { proc.Begin( ioc, desc ); }
void End() { proc.End(); }
int Class() { return CREATE_COMMAND; }
int ID() { return CID_TSPOTCREATE; }
MouseCallBack *MouseProc(int *numPoints) { *numPoints = 1000000; return &proc; }
ChangeForegroundCallback *ChangeFGProc() { return CHANGE_FG_SELECTED; }
BOOL ChangeFG( CommandMode *oldMode ) { return (oldMode->ChangeFGProc() != CHANGE_FG_SELECTED); }
void EnterMode() {
}
void ExitMode() {
}
BOOL IsSticky() { return FALSE; }
};
static TSpotCreateMode theTSpotCreateMode;
#endif
#if 0
void TSpotCreationManager::Begin( IObjCreate *ioc, ClassDesc *desc )
{
createInterface = ioc;
cDesc = desc;
attachedToNode = FALSE;
createCB = NULL;
lgtNode = NULL;
targNode = NULL;
lgtObject = NULL;
targObject = NULL;
CreateNewObject();
}
void TSpotCreationManager::End()
{
if ( lgtObject ) {
lgtObject->EndEditParams( (IObjParam*)createInterface, END_EDIT_REMOVEUI, NULL);
if ( !attachedToNode ) {
// RB 4-9-96: Normally the hold isn't holding when this
// happens, but it can be in certain situations (like a track view paste)
// Things get confused if it ends up with undo...
theHold.Suspend();
//delete lgtObject;
lgtObject->DeleteThis(); // JBW 11.1.99, this allows scripted plugin lights to delete cleanly
lgtObject = NULL;
theHold.Resume();
// RB 7/28/97: If something has been put on the undo stack since this object was created, we have to flush the undo stack.
if (theHold.GetGlobalPutCount()!=lastPutCount) {
GetSystemSetting(SYSSET_CLEAR_UNDO);
}
macroRec->Cancel(); // JBW 4/23/99
}
else if ( lgtNode ) {
// Get rid of the reference.
DeleteReference(0); // sets lgtNode = NULL
}
}
}
RefResult TSpotCreationManager::NotifyRefChanged(
Interval changeInt,
RefTargetHandle hTarget,
PartID& partID,
RefMessage message)
{
switch (message) {
case REFMSG_PRENOTIFY_PASTE:
case REFMSG_TARGET_SELECTIONCHANGE:
if ( ignoreSelectionChange ) {
break;
}
if (lgtObject && lgtNode==hTarget) {
// this will set camNode== NULL;
DeleteReference(0);
goto endEdit;
}
// fall through
case REFMSG_TARGET_DELETED:
if ( lgtObject && lgtNode==hTarget ) {
endEdit:
lgtObject->EndEditParams( (IObjParam*)createInterface, 0, NULL);
lgtObject = NULL;
lgtNode = NULL;
CreateNewObject();
attachedToNode = FALSE;
}
else if (targNode==hTarget) {
targNode = NULL;
targObject = NULL;
}
break;
}
return REF_SUCCEED;
}
void TSpotCreationManager::CreateNewObject()
{
lgtObject = (plRTLightBase *)cDesc->Create();
lastPutCount = theHold.GetGlobalPutCount();
macroRec->BeginCreate(cDesc); // JBW 4/23/99
// Start the edit params process
if ( lgtObject ) {
lgtObject->BeginEditParams( (IObjParam*)createInterface, BEGIN_EDIT_CREATE, NULL );
}
}
static void whoa(){};
static BOOL needToss;
int TSpotCreationManager::proc(
HWND hwnd,
int msg,
int point,
int flag,
IPoint2 m )
{
int res;
TSTR targName;
ViewExp *vpx = createInterface->GetViewport(hwnd);
assert( vpx );
switch ( msg ) {
case MOUSE_POINT:
switch ( point ) {
case 0:
pt0 = m;
assert( lgtObject );
vpx->CommitImplicitGrid(m, flag); //KENNY MERGE
if ( createInterface->SetActiveViewport(hwnd) ) {
return FALSE;
}
if (createInterface->IsCPEdgeOnInView()) {
res = FALSE;
goto done;
}
// if lights were hidden by category, re-display them
GetCOREInterface()->SetHideByCategoryFlags(
GetCOREInterface()->GetHideByCategoryFlags() & ~HIDE_LIGHTS);
if ( attachedToNode ) {
// send this one on its way
lgtObject->EndEditParams( (IObjParam*)createInterface, 0, NULL);
macroRec->EmitScript(); // JBW 4/23/99
// Get rid of the reference.
if (lgtNode)
DeleteReference(0);
// new object
CreateNewObject(); // creates lgtObject
}
needToss = theHold.GetGlobalPutCount()!=lastPutCount;
theHold.Begin(); // begin hold for undo
mat.IdentityMatrix();
// link it up
lgtNode = createInterface->CreateObjectNode( lgtObject);
attachedToNode = TRUE;
assert( lgtNode );
createCB = lgtObject->GetCreateMouseCallBack();
createInterface->SelectNode( lgtNode );
// Create target object and node
targObject = TRACKED_NEW TargetObject;
assert(targObject);
targNode = createInterface->CreateObjectNode( targObject);
assert(targNode);
targName = lgtNode->GetName();
targName += GetString(IDS_DB_DOT_TARGET);
targNode->SetName(targName);
// hook up camera to target using lookat controller.
createInterface->BindToTarget(lgtNode,targNode);
// Reference the new node so we'll get notifications.
MakeRefByID( FOREVER, 0, lgtNode);
// Position camera and target at first point then drag.
mat.IdentityMatrix();
//mat[3] = vpx->GetPointOnCP(m);
#ifdef _3D_CREATE
mat.SetTrans( vpx->SnapPoint(m,m,NULL,SNAP_IN_3D) );
#else
mat.SetTrans(vpx->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
#endif
createInterface->SetNodeTMRelConstPlane(lgtNode, mat);
createInterface->SetNodeTMRelConstPlane(targNode, mat);
lgtObject->Enable(1);
ignoreSelectionChange = TRUE;
createInterface->SelectNode( targNode,0);
ignoreSelectionChange = FALSE;
res = TRUE;
break;
case 1:
if (Length(m-pt0)<2)
goto abort;
//mat[3] = vpx->GetPointOnCP(m);
#ifdef _3D_CREATE
mat.SetTrans( vpx->SnapPoint(m,m,NULL,SNAP_IN_3D) );
#else
mat.SetTrans(vpx->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
#endif
macroRec->Disable(); // JBW 4/23/99
createInterface->SetNodeTMRelConstPlane(targNode, mat);
macroRec->Enable();
ignoreSelectionChange = TRUE;
createInterface->SelectNode( lgtNode);
ignoreSelectionChange = FALSE;
theHold.Accept(IDS_DS_CREATE);
createInterface->AddLightToScene(lgtNode);
createInterface->RedrawViews(createInterface->GetTime());
res = FALSE; // We're done
break;
}
break;
case MOUSE_MOVE:
//mat[3] = vpx->GetPointOnCP(m);
#ifdef _3D_CREATE
mat.SetTrans( vpx->SnapPoint(m,m,NULL,SNAP_IN_3D) );
#else
mat.SetTrans(vpx->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
#endif
macroRec->Disable(); // JBW 4/23/99
createInterface->SetNodeTMRelConstPlane(targNode, mat);
macroRec->Enable();
createInterface->RedrawViews(createInterface->GetTime());
macroRec->SetProperty(lgtObject, _T("target"), // JBW 4/23/99
mr_create, Class_ID(TARGET_CLASS_ID, 0), GEOMOBJECT_CLASS_ID, 1, _T("transform"), mr_matrix3, &mat);
res = TRUE;
break;
case MOUSE_FREEMOVE:
SetCursor(LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CROSS_HAIR)));
#ifdef _OSNAP
//Snap Preview
#ifdef _3D_CREATE
vpx->SnapPreview(m,m,NULL, SNAP_IN_3D);
#else
vpx->SnapPreview(m,m,NULL, SNAP_IN_PLANE);
#endif
#endif
vpx->TrackImplicitGrid(m); //KENNY MERGE
break;
case MOUSE_PROPCLICK:
// right click while between creations
createInterface->RemoveMode(NULL);
break;
case MOUSE_ABORT:
abort:
assert( lgtObject );
lgtObject->EndEditParams( (IObjParam*)createInterface,0,NULL);
// Toss the undo stack if param changes have been made
macroRec->Cancel(); // JBW 4/23/99
theHold.Cancel(); // deletes both the camera and target.
if (needToss)
GetSystemSetting(SYSSET_CLEAR_UNDO);
lgtNode = NULL;
targNode = NULL;
createInterface->RedrawViews(createInterface->GetTime());
CreateNewObject();
attachedToNode = FALSE;
res = FALSE;
}
done:
//KENNY MERGE
if ((res == CREATE_STOP)||(res==CREATE_ABORT))
vpx->ReleaseImplicitGrid();
createInterface->ReleaseViewport(vpx);
return res;
}
#endif