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.
 
 
 
 
 

524 lines
18 KiB

/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUICtrlGenerator Definitions //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUICtrlGenerator.h"
#include "pfGameGUIMgr.h"
#include "pfGUIControlMod.h"
#include "pfGUIDialogMod.h"
#include "pfGUIButtonMod.h"
#include "pfGUIDragBarCtrl.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIMenuItem.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayer.h"
#include "../plGImage/plMipmap.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../plDrawable/plDrawableSpans.h"
#include "../plDrawable/plDrawableGenerator.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plObjRefMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../plPipeline/plTextGenerator.h"
#include "../plScene/plPostEffectMod.h"
#include "../plScene/plSceneNode.h"
#include "../pnMessage/plClientMsg.h"
#include "../plMessage/plLayRefMsg.h"
#include "../pnMessage/plAttachMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUICtrlGenerator::pfGUICtrlGenerator()
{
strcpy( fFontFace, "Arial" );
fFontSize = 18;
}
pfGUICtrlGenerator::~pfGUICtrlGenerator()
{
Shutdown();
}
void pfGUICtrlGenerator::Shutdown( void )
{
int i;
// Destroy our scene nodes and dialogs
for( i = 0; i < fDynDlgNodes.GetCount(); i++ )
{
pfGameGUIMgr::GetInstance()->UnloadDialog( fDynDialogs[ i ] );
fDynDlgNodes[ i ]->GetKey()->UnRefObject();
}
fDynDlgNodes.Reset();
fDynDialogs.Reset();
for( i = 0; i < fTextGens.GetCount(); i++ )
delete fTextGens[ i ];
fTextGens.Reset();
}
//// Instance ////////////////////////////////////////////////////////////////
pfGUICtrlGenerator &pfGUICtrlGenerator::Instance( void )
{
static pfGUICtrlGenerator myInstance;
return myInstance;
}
//// IGetNextKeyName /////////////////////////////////////////////////////////
void pfGUICtrlGenerator::IGetNextKeyName( char *name, const char *prefix )
{
static UInt32 keyCount = 0;
sprintf( name, "%s%d", prefix, keyCount++ );
}
//// IAddKey /////////////////////////////////////////////////////////////////
plKey pfGUICtrlGenerator::IAddKey( hsKeyedObject *ko, const char *prefix )
{
char keyName[ 128 ];
IGetNextKeyName( keyName, prefix );
return hsgResMgr::ResMgr()->NewKey( keyName, ko, plLocation::kGlobalFixedLoc );
}
//// SetFont /////////////////////////////////////////////////////////////////
void pfGUICtrlGenerator::SetFont( const char *face, UInt16 size )
{
strcpy( fFontFace, face );
fFontSize = size;
}
//// ICreateSolidMaterial ////////////////////////////////////////////////////
// Creates a material with no texture, just color.
hsGMaterial *pfGUICtrlGenerator::ICreateSolidMaterial( hsColorRGBA &color )
{
hsColorRGBA black;
// Create a material with a simple blank layer, fully ambient
hsGMaterial *material = TRACKED_NEW hsGMaterial;
IAddKey( material, "GUIMaterial" );
plLayer *lay = material->MakeBaseLayer();
black.Set( 0.f,0.f,0.f,1.f );
lay->SetRuntimeColor( black );
lay->SetPreshadeColor( black );
lay->SetAmbientColor( color );
return material;
}
//// ICreateTextMaterial /////////////////////////////////////////////////////
// Creates a material with a texture that has a string centered on it.
hsGMaterial *pfGUICtrlGenerator::ICreateTextMaterial( const char *text, hsColorRGBA &bgColor,
hsColorRGBA &textColor, float objWidth, float objHeight )
{
UInt16 pixWidth, pixHeight, strWidth, strHeight;
hsColorRGBA black, white;
// Guess at some pixel width and heights we want. We're guessing b/c we want it to look reasonably
// good on the screen, but we don't know exactly how big is big, so we guess
pixWidth = (UInt16)(objWidth * 64.f);
pixHeight = (UInt16)(objHeight * 64.f);
// Create blank mipmap
plMipmap *bitmap = TRACKED_NEW plMipmap( 1, 1, plMipmap::kRGB32Config, 1 );
IAddKey( bitmap, "GUIMipmap" );
// Create textGen to write string with
plTextGenerator *textGen = TRACKED_NEW plTextGenerator( bitmap, pixWidth, pixHeight );
textGen->SetFont( fFontFace, (UInt16)fFontSize );
textGen->ClearToColor( bgColor );
textGen->SetTextColor( textColor );
strWidth = textGen->CalcStringWidth( text, &strHeight );
textGen->DrawString( ( pixWidth - strWidth ) >> 1, ( pixHeight - strHeight ) >> 1, text );
textGen->FlushToHost();
fTextGens.Append( textGen );
// Create a material with a simple blank layer, fully ambient
hsGMaterial *material = TRACKED_NEW hsGMaterial;
IAddKey( material, "GUIMaterial" );
plLayer *lay = material->MakeBaseLayer();
white.Set( 1.f,1.f,1.f,1.f );
black.Set( 0.f,0.f,0.f,1.f );
lay->SetRuntimeColor( black );
lay->SetPreshadeColor( black );
lay->SetAmbientColor( white );
hsgResMgr::ResMgr()->AddViaNotify( bitmap->GetKey(), TRACKED_NEW plLayRefMsg( lay->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef );
// lay->SetTexture( bitmap );
lay->SetTransform( textGen->GetLayerTransform() );
return material;
}
//// GenerateDialog //////////////////////////////////////////////////////////
void pfGUICtrlGenerator::GenerateDialog( const char *name )
{
IGenerateDialog( name, 20.f, false );
}
//// IGenSceneObject /////////////////////////////////////////////////////////
plSceneObject *pfGUICtrlGenerator::IGenSceneObject( pfGUIDialogMod *dlg, plDrawable *myDraw, plSceneObject *parent,
hsMatrix44 *l2w, hsMatrix44 *w2l )
{
plKey snKey = ( dlg != nil ) ? ( dlg->GetTarget() != nil ? dlg->GetTarget()->GetSceneNode() : nil ) : nil;
if( snKey == nil )
snKey = fDynDlgNodes.Peek()->GetKey();
hsgResMgr::ResMgr()->SendRef( myDraw->GetKey(), TRACKED_NEW plNodeRefMsg( snKey, plRefMsg::kOnCreate, 0, plNodeRefMsg::kDrawable ), plRefFlags::kActiveRef );
plDrawInterface *newDI = TRACKED_NEW plDrawInterface;
IAddKey( newDI, "GUIDrawIFace" );
plSceneObject *newObj = TRACKED_NEW plSceneObject;
IAddKey( newObj, "GUISceneObject" );
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface;
IAddKey( newCI, "GUICoordIFace" );
hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( newDI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( myDraw->GetKey(), TRACKED_NEW plIntRefMsg( newDI->GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kDrawable ), plRefFlags::kActiveRef );
if( parent == nil )
{
parent = ( fDynDragBars.GetCount() > 0 ) ? fDynDragBars.Peek() : nil;
if( parent == nil )
parent = dlg->GetTarget();
}
if( parent != nil )
// hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plIntRefMsg( parent->GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kChild ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plAttachMsg( parent->GetKey(), nil, plRefMsg::kOnRequest ), plRefFlags::kActiveRef );
newObj->SetSceneNode( snKey );
if( l2w != nil )
{
newObj->SetTransform( *l2w, *w2l );
// newCI->SetLocalToParent( *l2w, *w2l );
// myDraw->SetTransform( -1, *l2w, *w2l );
}
return newObj;
}
//// GenerateRectButton //////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::GenerateRectButton( const char *title, float x, float y, float width, float height,
const char *consoleCmd, hsColorRGBA &color, hsColorRGBA &textColor )
{
hsGMaterial *material;
hsMatrix44 l2w, w2l;
hsVector3 vec;
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Get us a material
material = ICreateTextMaterial( title, color, textColor, width * 20.f, height * 20.f );
pfGUIButtonMod *but = CreateRectButton( dlgToAddTo, title, x, y, width, height, material );
if( but != nil )
but->SetHandler( TRACKED_NEW pfGUIConsoleCmdProc( consoleCmd ) );
return but;
}
//// CreateRectButton ////////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::CreateRectButton( pfGUIDialogMod *parent, const char *title, float x, float y, float width, float height,
hsGMaterial *material, hsBool asMenuItem )
{
wchar_t *wTitle = hsStringToWString(title);
pfGUIButtonMod *retVal = CreateRectButton(parent,wTitle,x,y,width,height,material,asMenuItem);
delete [] wTitle;
return retVal;
}
pfGUIButtonMod *pfGUICtrlGenerator::CreateRectButton( pfGUIDialogMod *parent, const wchar_t *title, float x, float y, float width, float height,
hsGMaterial *material, hsBool asMenuItem )
{
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
width *= 20.f;
height *= 20.f;
// Create drawable that is rectangular
l2w.Reset();
hsPoint3 corner( x, -y, -100 );
hsVector3 xVec( width, 0, 0 ), yVec( 0, height, 0 ), zVec( 0, 0, 0.1f );
myDraw = plDrawableGenerator::GeneratePlanarDrawable( corner, xVec, yVec, material, l2w );
plSceneObject *newObj = IGenSceneObject( parent, myDraw );
pfGUIButtonMod *newBtn = asMenuItem ? TRACKED_NEW pfGUIMenuItem : TRACKED_NEW pfGUIButtonMod;
IAddKey( newBtn, "GUIButton" );
hsgResMgr::ResMgr()->SendRef( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
parent->AddControl( newBtn );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plGenRefMsg( parent->GetKey(), plRefMsg::kOnCreate, parent->GetNumControls() - 1, pfGUIDialogMod::kControlRef ), plRefFlags::kActiveRef );
return newBtn;
}
//// GenerateSphereButton ////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::GenerateSphereButton( float x, float y, float radius,
const char *consoleCmd, hsColorRGBA &color )
{
hsGMaterial *material;
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
hsPoint3 pt( x, -y, -100.f );
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
radius *= 20.f;
// Get us a material
material = ICreateSolidMaterial( color );
// Create drawable that is rectangular
l2w.Reset();
// We bump up the quality since we're actually far closer to these things then the normal
// world camera would put us
myDraw = plDrawableGenerator::GenerateSphericalDrawable( pt, radius, material, l2w,
false, nil, nil, nil, 100.f );
vec.Set( x, -y, 0 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plSceneObject *newObj = IGenSceneObject( dlgToAddTo, myDraw );//, nil, &l2w, &w2l );
pfGUIButtonMod *newBtn = TRACKED_NEW pfGUIButtonMod;
IAddKey( newBtn, "GUIButton" );
newBtn->SetHandler( TRACKED_NEW pfGUIConsoleCmdProc( consoleCmd ) );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
dlgToAddTo->AddControl( newBtn );
return newBtn;
}
//// GenerateDragBar //////////////////////////////////////////////////////
pfGUIDragBarCtrl *pfGUICtrlGenerator::GenerateDragBar( float x, float y, float width, float height, hsColorRGBA &color )
{
hsGMaterial *material;
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
width *= 20.f;
height *= 20.f;
// Get us a material
material = ICreateSolidMaterial( color );
// Create drawable that is rectangular
l2w.Reset();
hsPoint3 corner( x, -y, -100 );//x - width / 2.f, -y - height / 2.f, -100 );
hsVector3 xVec( width, 0, 0 ), yVec( 0, height, 0 ), zVec( 0, 0, 0.1f );
myDraw = plDrawableGenerator::GenerateBoxDrawable( corner, xVec, yVec, zVec,/*width, height, 0.01f, */material, l2w );
// Drag bars are special--everything else gets attached to them and they get attached to the dialog
vec.Set( x, -y, -100 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plSceneObject *newObj = IGenSceneObject( dlgToAddTo, myDraw, dlgToAddTo->GetTarget(), &l2w, &w2l );
fDynDragBars[ fDynDragBars.GetCount() - 1 ] = newObj;
pfGUIDragBarCtrl *newBtn = TRACKED_NEW pfGUIDragBarCtrl;
IAddKey( newBtn, "GUIDragBar" );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
dlgToAddTo->AddControl( newBtn );
/* vec.Set( -x, y, 100 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plCoordinateInterface *ci = (plCoordinateInterface *)dlgToAddTo->GetTarget()->GetCoordinateInterface();
ci->SetLocalToParent( l2w, w2l );
*/
return newBtn;
}
//// IGetDialog //////////////////////////////////////////////////////////////
pfGUIDialogMod *pfGUICtrlGenerator::IGetDialog( void )
{
if( fDynDialogs.GetCount() == 0 )
IGenerateDialog( "GUIBaseDynamicDlg", 20.f );
hsAssert( fDynDialogs.GetCount() > 0, "Unable to get a dynamic dialog to add buttons to" );
return fDynDialogs.Peek();
}
//// IGenerateDialog /////////////////////////////////////////////////////////
pfGUIDialogMod *pfGUICtrlGenerator::IGenerateDialog( const char *name, float scrnWidth, hsBool show )
{
float fovX, fovY;
plSceneNode *node;
pfGUIDialogMod *dialog;
// Create the rendermod
plPostEffectMod *renderMod = TRACKED_NEW plPostEffectMod;
IAddKey( renderMod, "GUIRenderMod" );
renderMod->SetHither( 0.5f );
renderMod->SetYon( 200.f );
// fovX should be such that scrnWidth is the projected width at z=100
fovX = atan( scrnWidth / ( 2.f * 100.f ) ) * 2.f;
fovY = fovX;// * 3.f / 4.f;
renderMod->SetFovX( fovX * 180.f / hsScalarPI );
renderMod->SetFovY( fovY * 180.f / hsScalarPI );
// Create the sceneNode to go with it
node = TRACKED_NEW plSceneNode;
IAddKey( node, "GUISceneNode" );
node->GetKey()->RefObject();
fDynDlgNodes.Append( node );
fDynDragBars.Append( nil );
hsgResMgr::ResMgr()->AddViaNotify( node->GetKey(), TRACKED_NEW plGenRefMsg( renderMod->GetKey(), plRefMsg::kOnCreate, 0, plPostEffectMod::kNodeRef ), plRefFlags::kPassiveRef );
// Create the dialog
dialog = TRACKED_NEW pfGUIDialogMod;
IAddKey( dialog, "GUIDialog" );
dialog->SetRenderMod( renderMod );
dialog->SetName( name );
// Create the dummy scene object to hold the dialog
plSceneObject *newObj = TRACKED_NEW plSceneObject;
IAddKey( newObj, "GUISceneObject" );
// *#&$(*@&#$ need a coordIface...
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface;
IAddKey( newCI, "GUICoordIFace" );
hsMatrix44 l2w, w2l;
l2w.Reset();
// l2w.NotIdentity();
l2w.GetInverse( &w2l );
// Using SendRef here because AddViaNotify will queue the messages up, which doesn't do us any good
// if we need these refs right away
hsgResMgr::ResMgr()->SendRef( dialog->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( renderMod->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
// Add the dialog to the GUI mgr
plGenRefMsg *refMsg = TRACKED_NEW plGenRefMsg( pfGameGUIMgr::GetInstance()->GetKey(),
plRefMsg::kOnCreate, 0, pfGameGUIMgr::kDlgModRef );
hsgResMgr::ResMgr()->AddViaNotify( dialog->GetKey(), refMsg, plRefFlags::kActiveRef );
newObj->SetSceneNode( node->GetKey() );
newObj->SetTransform( l2w, w2l );
// newCI->SetLocalToParent( l2w, w2l );
if( show )
pfGameGUIMgr::GetInstance()->ShowDialog( dialog );
fDynDialogs.Append( dialog );
return dialog;
}