/*==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==*/ /////////////////////////////////////////////////////////////////////////////// // // // plRTProjDirLight.cpp - Functions for the Projected Directional MAX light // // Cyan, Inc. // // // //// Version History ////////////////////////////////////////////////////////// // // // 8.2.2001 mcn - Created. // // // /////////////////////////////////////////////////////////////////////////////// #include "HeadSpin.h" #include "plRTProjDirLight.h" #include "plRTProjDirLightClassDesc.h" #include "iparamm2.h" #include "../MaxPlasmaMtls/Layers/plLayerTex.h" #include "../MaxPlasmaMtls/Layers/plLayerTexBitmapPB.h" #include "../MaxComponent/plMaxAnimUtils.h" #include "plRTObjLightDesc.h" #include "plRTLightBaseAnimDlgProc.h" //// Static ClassDesc2 Get Functions ////////////////////////////////////////// plRTProjDirLightDesc plRTProjDirLightDesc::fStaticDesc; //// Dialog Proc ////////////////////////////////////////////////////////////// class plProjDirDlgProc : public plBaseLightProc { public: BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { IParamBlock2 *pb = map->GetParamBlock(); plRTProjDirLight *lite = (plRTProjDirLight *)pb->GetOwner(); PBBitmap *bitmap; plLayerTex *layer = (plLayerTex *)lite->GetProjMap(); ICustButton *bmSelectBtn; switch( msg ) { case WM_COMMAND: if( LOWORD( wParam ) == IDC_PROJ_MAPNAME ) { BOOL selectedNewBitmap = layer->HandleBitmapSelection(); if( selectedNewBitmap ) { bmSelectBtn = GetICustButton( GetDlgItem( hWnd, IDC_PROJ_MAPNAME ) ); bitmap = layer->GetPBBitmap(); bmSelectBtn->SetText( bitmap != nil ? (TCHAR *)bitmap->bi.Filename() : ""); ReleaseICustButton( bmSelectBtn ); } return false; } break; case WM_INITDIALOG: // Set projection map bitmap name bmSelectBtn = GetICustButton( GetDlgItem( hWnd, IDC_PROJ_MAPNAME ) ); if( bmSelectBtn != nil ) { bitmap = ( layer == nil ) ? nil : layer->GetPBBitmap(); if( bitmap != nil ) bmSelectBtn->SetText( (TCHAR *)bitmap->bi.Filename() ); else bmSelectBtn->SetText( _T( "" ) ); ReleaseICustButton( bmSelectBtn ); } break; } return plBaseLightProc::DlgProc( t, map, hWnd, msg, wParam, lParam ); } void DeleteThis() {}; }; static plProjDirDlgProc gPPDirLiteDlgProc; /// Include for the ParamBlock2 definition #include "plRTProjDirLightPBDec.h" /////////////////////////////////////////////////////////////////////////////// //// plRTProjPBAccessor Class Functions /////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// plRTProjPBAccessor plRTProjPBAccessor::fAccessor; void plRTProjPBAccessor::Set( PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) { plRTProjDirLight *obj = (plRTProjDirLight *)owner; IParamBlock2 *pb = obj->GetParamBlockByID( plRTProjDirLight::kBlkProj ); switch( id ) { case plRTProjDirLight::kProjMap: /* { if( pb->GetMap() ) pb->GetMap()->Invalidate( plRTProjDirLight::kProjMap ); PBBitmap *thisMap = val.bm; obj->SetProjMap( &thisMap->bi ); } */ break; default: break; } } void plRTProjPBAccessor::Get( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid ) { } /////////////////////////////////////////////////////////////////////////////// //// Projected Directional Light ////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// plRTProjDirLight::plRTProjDirLight() { fIP = nil; fLightPB = nil; fProjPB = nil; fClassDesc = plRTProjDirLightDesc::GetDesc(); fClassDesc->MakeAutoParamBlocks( this ); fLightPB->SetValue(kLightColor, 0, Color(255,255,255)); SetHSVColor(0, Point3(255, 255, 255)); fTex = nil; meshBuilt = 0; IBuildMeshes(true); } ObjLightDesc *plRTProjDirLight::CreateLightDesc( INode *n, BOOL forceShadowBuf ) { return TRACKED_NEW DirLight( n, forceShadowBuf ); } RefTargetHandle plRTProjDirLight::Clone( RemapDir &remap ) { plRTProjDirLight *obj = TRACKED_NEW plRTProjDirLight; obj->ReplaceReference( kRefDirLight, fLightPB->Clone( remap ) ); BaseClone( this, obj, remap ); return obj; } //// SubAnim ///////////////////////////////////////////////////////////////// Animatable *plRTProjDirLight::SubAnim( int i ) { switch( i ) { case 0: return (Animatable *)fLightPB; case 1: return (Animatable *)fProjPB; default: return nil; } } //// SubAnimName ///////////////////////////////////////////////////////////// TSTR plRTProjDirLight::SubAnimName( int i ) { switch( i ) { case 0: return fLightPB->GetLocalName(); case 1: return fProjPB->GetLocalName(); default: return TSTR( "" ); } } //// GetReference //////////////////////////////////////////////////////////// RefTargetHandle plRTProjDirLight::GetReference( int i ) { switch( i ) { case kRefMainRollout: return (RefTargetHandle)fLightPB; case kRefProjRollout: return (RefTargetHandle)fProjPB; default: return plRTLightBase::GetReference( i ); } } //// SetReference //////////////////////////////////////////////////////////// void plRTProjDirLight::SetReference( int ref, RefTargetHandle rtarg ) { switch( ref ) { case kRefMainRollout: fLightPB = (IParamBlock2 *)rtarg; break; case kRefProjRollout: fProjPB = (IParamBlock2 *)rtarg; break; default: plRTLightBase::SetReference( ref, rtarg ); break; } } //// ParamBlock Functions //////////////////////////////////////////////////// int plRTProjDirLight::NumParamBlocks() { return plRTLightBase::NumParamBlocks() + 1; } IParamBlock2 *plRTProjDirLight::GetParamBlock( int i ) { switch ( i ) { case 2: return fProjPB; default: return plRTLightBase::GetParamBlock( i ); } } IParamBlock2 *plRTProjDirLight::GetParamBlockByID( BlockID id ) { if( fProjPB->ID() == id ) return fProjPB; else return plRTLightBase::GetParamBlockByID( id ); } //// GetProjMap ////////////////////////////////////////////////////////////// Texmap *plRTProjDirLight::GetProjMap() { // If we don't have one, create one plLayerTex *layer = (plLayerTex *)fProjPB->GetTexmap( kTexmap, 0 ); if( layer == nil || layer->ClassID() != LAYER_TEX_CLASS_ID ) { layer = TRACKED_NEW plLayerTex; fProjPB->SetValue( kTexmap, 0, (Texmap *)layer ); IParamBlock2 *bitmapPB = layer->GetParamBlockByID( plLayerTex::kBlkBitmap ); bitmapPB->SetValue( kBmpUseBitmap, 0, 1 ); } // Backwards compatability here PBBitmap *bitmap = fProjPB->GetBitmap( kProjMap, 0 ); if( bitmap != nil ) { layer->SetBitmap( &bitmap->bi ); fProjPB->SetValue( kProjMap, 0, (PBBitmap *)nil ); } if( layer ) { const char* dbgTexName = layer->GetName(); IParamBlock2 *bitmapPB = layer->GetParamBlockByID(plLayerTex::kBlkBitmap); hsAssert(bitmapPB, "LayerTex with no param block"); int noCompress = fProjPB->GetInt(kProjNoCompress); int noMip = fProjPB->GetInt(kProjNoMip); bitmapPB->SetValue(kBmpNonCompressed, TimeValue(0), noCompress); bitmapPB->SetValue(kBmpNoFilter, TimeValue(0), noMip); } return (Texmap *)layer; } //// IBuildMeshes //////////////////////////////////////////////////////////// void plRTProjDirLight::IBuildMeshes( BOOL isnew ) { BuildStaticMeshes(); fMesh = staticMesh[ plRTLightBase::RT_OMNI + 1 ]; } //// GetLocalBoundBox //////////////////////////////////////////////////////// void plRTProjDirLight::GetLocalBoundBox( TimeValue t, INode *node, ViewExp *vpt, Box3 &box ) { Point3 loc = node->GetObjectTM( t ).GetTrans(); float scaleFactor = vpt->NonScalingObjectSize() * vpt->GetVPWorldWidth( loc ) / 360.0f; float width, height, depth; box = fMesh.getBoundingBox(); // Because we want to scale about the origin, not the box center, we have to do this funky offset Point3 boxCenter = box.Center(); box.Translate( -boxCenter ); box.Scale( scaleFactor ); boxCenter *= scaleFactor; box.Translate( boxCenter ); if( ( extDispFlags & EXT_DISP_ONLY_SELECTED ) ) { fProjPB->GetValue( kWidth, t, width, FOREVER ); fProjPB->GetValue( kHeight, t, height, FOREVER ); fProjPB->GetValue( kRange, t, depth, FOREVER ); width /= 2.f; height /= 2.f; box += Point3( -width, -height, 0.f ); box += Point3( width, height, -depth ); } } //// DrawConeAndLine ///////////////////////////////////////////////////////// int plRTProjDirLight::DrawConeAndLine( TimeValue t, INode* inode, GraphicsWindow *gw, int drawing ) { Matrix3 tm = inode->GetObjectTM( t ); gw->setTransform( tm ); gw->clearHitCode(); if( extDispFlags & EXT_DISP_ONLY_SELECTED ) DrawCone( t, gw, 500 ); return gw->checkHitCode(); } //// DrawCone //////////////////////////////////////////////////////////////// // Function called by MAX to render the cone shape in the viewport for this // light. Note that this is the cone, not the actual object itself! void plRTProjDirLight::DrawCone( TimeValue t, GraphicsWindow *gw, float dist ) { Point3 nearPts[ 5 ], farPts[ 5 ], u[ 3 ]; int i; float width, height; // Get values fProjPB->GetValue( kWidth, t, width, FOREVER ); fProjPB->GetValue( kHeight, t, height, FOREVER ); fProjPB->GetValue( kRange, t, dist, FOREVER ); // Draw a rectangle showing the extents of the light (width, height and depth) IBuildRectangle( width, height, 0, nearPts ); IBuildRectangle( width, height, -dist, farPts ); gw->setColor( LINE_COLOR, GetUIColor( COLOR_HOTSPOT ) ); gw->polyline( 4, nearPts, nil, nil, true, nil ); gw->polyline( 4, farPts, nil, nil, true, nil ); for( i = 0; i < 4; i++ ) { u[ 0 ] = nearPts[ i ]; u[ 1 ] = farPts[ i ]; gw->polyline( 2, u, nil, nil, false, nil ); } } //// IBuildRectangle ///////////////////////////////////////////////////////// void plRTProjDirLight::IBuildRectangle( float width, float height, float z, Point3 *pts ) { width /= 2.f; height /= 2.f; pts[ 0 ] = Point3( -width, -height, z ); pts[ 1 ] = Point3( width, -height, z ); pts[ 2 ] = Point3( width, height, z ); pts[ 3 ] = Point3( -width, height, z ); } //// GetFallsize ///////////////////////////////////////////////////////////// // To get using-light-as-camera-viewport to work float plRTProjDirLight::GetFallsize( TimeValue t, Interval &valid ) { if( fProjPB == nil ) return -1.f; return fProjPB->GetFloat( kWidth, t ); } //// GetAspect /////////////////////////////////////////////////////////////// // To get using-light-as-camera-viewport to work float plRTProjDirLight::GetAspect( TimeValue t, Interval &valid ) { if( fProjPB == nil ) return -1.f; return( fProjPB->GetFloat( kHeight, t ) / fProjPB->GetFloat( kWidth, t ) ); } //// GetTDist //////////////////////////////////////////////////////////////// // To get using-light-as-camera-viewport to work float plRTProjDirLight::GetTDist( TimeValue t, Interval &valid ) { return 0.f; if( fProjPB == nil ) return -1.f; return fProjPB->GetFloat( kRange, t ); } //// SetFallsize ///////////////////////////////////////////////////////////// // To get using-light-as-camera-viewport to work void plRTProjDirLight::SetFallsize( TimeValue time, float f ) { if( fProjPB != nil ) fProjPB->SetValue( kWidth, time, f ); } //// EvalLightState ////////////////////////////////////////////////////////// // To get using-light-as-camera-viewport to work RefResult plRTProjDirLight::EvalLightState( TimeValue t, Interval& valid, LightState *ls ) { ls->type = DIRECT_LGT; 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 ); float fall = fProjPB->GetFloat( kWidth, t ); if( fall < fProjPB->GetFloat( kHeight, t ) ) fall = fProjPB->GetFloat( kHeight, t ); ls->hotsize = ls->fallsize = fall / 2.f; ls->useNearAtten = false; ls->useAtten = false; ls->shape = RECT_LIGHT; ls->aspect = fProjPB->GetFloat( kHeight, t ) / fProjPB->GetFloat( kWidth, t ); ls->overshoot = false; ls->shadow = false; ls->ambientOnly = false; ls->affectDiffuse = fLightPB->GetInt( kAffectDiffuse, t ); ls->affectSpecular = fLightPB->GetInt( kSpec, t ); return REF_SUCCEED; }