1 //
// C++ Implementation: AttributeObserver
//
// Description:
//
//
// Author: Erik Hjortsberg <erik.hjortsberg@iteam.se>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "AttributeObserver.h"
#include <Eris/Entity.h>
#include "services/logging/LoggingService.h"
namespace EmberOgre {
33 AttributeObserver::AttributeObserver( Eris::Entity* entity, const std::string& attributeName )
: mSlot( sigc::mem_fun( *this, &AttributeObserver::attributeChanged ) )
{
if ( entity ) {
entity->observe( attributeName, mSlot );
} else {
S_LOG_WARNING( "Tried to observer the attribute " << attributeName << " or a null entity." );
}
}
43 AttributeObserver::~AttributeObserver( )
{
mSlot.disconnect( );
}
48 void AttributeObserver::attributeChanged( const Atlas::Message::Element& attributeValue )
{
EventChanged.emit( attributeValue );
}
}
1 //
// C++ Interface: AttributeObserver
//
// Description:
//
//
// Author: Erik Hjortsberg <erik.hjortsberg@iteam.se>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREATTRIBUTEOBSERVER_H
#define EMBEROGREATTRIBUTEOBSERVER_H
#include <sigc++/trackable.h>
#include <Eris/Entity.h>
namespace Eris {
31 class Entity;
}
namespace EmberOgre {
/**
Observes changes to a specific attribute and emits a signal.
@author Erik Hjortsberg <erik.hjortsberg@iteam.se>
*/
40 class AttributeObserver : public sigc::trackable
{
public:
44 AttributeObserver( Eris::Entity* entity, const std::string& attributeName );
45 ~AttributeObserver( );
47 sigc::signal<void, const Atlas::Message::Element&> EventChanged;
protected:
50 Eris::Entity::AttrChangedSlot mSlot;
52 void attributeChanged( const Atlas::Message::Element& attributeValue );
};
}
#endif
1 /*
Avatar.cpp by Erik Hjortsberg
Copyright ( C ) 2002 Miguel Guzman, Erik Hjortsberg & The Worldforge
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Avatar.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <typeinfo>
#include "services/EmberServices.h"
#include "services/server/ServerService.h"
#include "services/config/ConfigService.h"
// #include "services/sound/SoundService.h"
#include "EmberEntity.h"
#include "EmberPhysicalEntity.h"
#include "AvatarController.h"
#include "AvatarCamera.h"
#include "AvatarEmberEntity.h"
#include "model/Model.h"
#include "model/SubModel.h"
#include "EmberOgre.h"
#include "MathConverter.h"
#include "input/Input.h"
#include <Eris/Avatar.h>
#include <Eris/Connection.h>
#include <Eris/TypeInfo.h>
namespace EmberOgre {
54 Avatar::Avatar( )
: mErisAvatarEntity( 0 ), mHasChangedLocation( false )
{
mTimeSinceLastServerMessage = 0;
setMinIntervalOfRotationChanges( 1000 ); //milliseconds
mAccumulatedHorizontalRotation = 0;
mThresholdDegreesOfYawForAvatarRotation = 100;
///these are the defaults, but if anything is set in the config file that will override these values as updateFromConfig is called
mWalkSpeed = 2.47;
mRunSpeed = 5; ///5 seems to be the max speed in cyphesis
/// Create the Avatar tree of nodes, with a base entity
/// and attach all the needed cameras
createAvatar( );
Ogre::Root::getSingleton( ).addFrameListener( this );
Ember::EmberServices::getSingletonPtr( )->getConfigService( )->EventChangedConfigItem.connect( sigc::mem_fun( *this, &Avatar::ConfigService_EventChangedConfigItem ) );
///update values from the config
updateFromConfig( );
}
82 Avatar::~Avatar( )
{
}
87 void Avatar::setMinIntervalOfRotationChanges( Ogre::Real milliseconds )
{
mMinIntervalOfRotationChanges = milliseconds;
}
92 void Avatar::createAvatar( )
{
// The avatar itself
mAvatarNode = static_cast<Ogre::SceneNode*>( EmberOgre::getSingleton( ).getSceneManager( )->getRootSceneNode( )->createChild( ) );
mAvatarNode->setPosition( Ogre::Vector3( 0, 0, 0 ) );
//mAvatarNode->setOrientation( 0, 1, 0, 0 );
//mAvatarNode->setScale( Ogre::Vector3( 0.01, 0.01, 0.01 ) );
/* // Model Node and Entity for display
// TODO: do also the scaling here! That way the other nodes can be positioned in their real places
mAvatarModelNode = static_cast<Ogre::SceneNode*>( mAvatarNode->createChild( "AvatarModelNode" ) );
Model* model = new Model( "AvatarEntity" );
model->create( "settler" );
// Model* model = Model::Create( "spider.modeldef.xml", "AvatarEntity" );
//Model::Create( "malebuilder.modeldef.xml", "AvatarEntity1" );
mAvatarModel = model;
mAvatarModelNode->attachObject( mAvatarModel );
mAvatarModelNode->rotate( Ogre::Vector3::UNIT_Y, ( Ogre::Degree )90 );*/
/* Ogre::Light* light = mSceneMgr->createLight( "AvatarLight__" );
light->setType( Ogre::Light::LT_POINT );
light->setCastShadows( true );
light->setDiffuseColour( 0.6, 0.6, 0.6 );
//light->setSpecularColour( 1, 1, 1 );
light->setAttenuation( 50, 1, 0.0005, 0 );
mAvatarModelNode->attachObject( light );*/
//
// mAvatarModelNode->showBoundingBox( true );
}
129 bool Avatar::frameStarted( const Ogre::FrameEvent & event )
{
if ( mEntitiesToBeAddedToInventory.size( ) > 0 ) {
std::set<Eris::Entity*>::iterator I = mEntitiesToBeAddedToInventory.begin( );
std::set<Eris::Entity*>::iterator I_end = mEntitiesToBeAddedToInventory.end( );
for ( ; I != I_end; ++I ) {
//no need to do dynamic cast here
EmberEntity* emberEntity = static_cast<EmberEntity*>( *I );
EventAddedEntityToInventory.emit( emberEntity );
}
mEntitiesToBeAddedToInventory.clear( );
}
/* if ( mEntitiesToBeRemovedFromInventory.size( ) > 0 ) {
std::set<Eris::Entity*>::iterator J = mEntitiesToBeRemovedFromInventory.begin( );
std::set<Eris::Entity*>::iterator J_end = mEntitiesToBeRemovedFromInventory.end( );
for ( ; J != J_end; ++J ) {
EmberEntity* emberEntity = dynamic_cast<EmberEntity*>( *J );
if ( emberEntity )
EventRemovedEntityFromInventory.emit( emberEntity );
}
mEntitiesToBeRemovedFromInventory.clear( );
}*/
return true;
}
163 void Avatar::updateFrame( AvatarControllerMovement& movement )
{
///for now we'll just rotate without notifying the server
///except when moving!
attemptRotate( movement );
///this next method will however send send stuff to the server
attemptMove( movement );
///only adjust if there is actual movement. If we adjust when there's only rotation we'll get a strange jerky effect ( some bug I guess )
if ( movement.isMoving ) {
adjustAvatarToNewPosition( &movement );
}
}
181 void Avatar::attemptMove( AvatarControllerMovement& movement )
{
Ogre::Vector3 move = movement.movementDirection;
bool isRunning = movement.mode == AvatarMovementMode::MM_RUN;
Ogre::Real timeSlice = movement.timeSlice;
float speed = isRunning ? mRunSpeed : mWalkSpeed;
Ogre::Vector3 rawVelocity = move * speed;
///first we'll register the current state in newMovementState and compare to mCurrentMovementState
///that way we'll only send stuff to the server if our movement changes
AvatarMovementState newMovementState;
newMovementState.orientation = mAvatarNode->getOrientation( );
newMovementState.velocity = rawVelocity;// * newMovementState.orientation.xAxis( );
if ( move != Ogre::Vector3::ZERO ) {
newMovementState.isMoving = true;
newMovementState.isRunning = isRunning;
} else {
newMovementState.isMoving = false;
newMovementState.isRunning = false;
}
bool sendToServer = false;
//first we check if we are already moving
if ( !mCurrentMovementState.isMoving ) {
//we are not moving. Should we start to move?
if ( newMovementState.isMoving ) {
//we'll start moving
//let's send the movement command to the server
sendToServer = true;
} else if ( !( newMovementState.orientation == mMovementStateAtLastServerMessage.orientation ) ) {
//we have rotated since last server update
//let's see if it's ok to send server message
//if not we have to wait some more frames until we'll send an update
if ( isOkayToSendRotationMovementChangeToServer( ) ) {
sendToServer = true;
}
}
} else {
//we are already moving
//let's see if we've changed speed or direction or even stopped
if ( !newMovementState.isMoving ) {
S_LOG_VERBOSE( "Avatar stopped moving." );
//we have stopped; we must alert the server
sendToServer = true;
} else if ( newMovementState.velocity != mCurrentMovementState.velocity || !( newMovementState.orientation == mCurrentMovementState.orientation ) ){
//either the speed or the direction has changed
sendToServer = true;
}
}
if ( sendToServer ) {
S_LOG_VERBOSE( "Sending move op to server." );
mMovementStateAtBeginningOfMovement = newMovementState;
mMovementStateAtLastServerMessage = newMovementState;
mTimeSinceLastServerMessage = 0;
//for now we'll only send velocity
Ember::EmberServices::getSingletonPtr( )->getServerService( )->moveInDirection( Ogre2Atlas_Vector3( newMovementState.orientation * newMovementState.velocity ), Ogre2Atlas( newMovementState.orientation ) );
// Ember::EmberServices::getSingletonPtr( )->getServerService( )->moveInDirection( Ogre2Atlas( mCurrentMovementState.velocity ), Ogre2Atlas( mCurrentMovementState.orientation ) );
} else {
mTimeSinceLastServerMessage += timeSlice * 1000;
}
if ( newMovementState.isMoving ) {
//do the actual movement of the avatar node
mAvatarNode->translate( mAvatarNode->getOrientation( ) * ( rawVelocity * timeSlice ) );
}
mCurrentMovementState = newMovementState;
}
259 void Avatar::adjustAvatarToNewPosition( AvatarControllerMovement* movement )
{
///allow the eris entity to adjust to the containing node
if ( mErisAvatarEntity ) {
mErisAvatarEntity->adjustPosition( );
}
// MotionManager::getSingleton( ).adjustHeightPositionForNode( mAvatarNode );
}
269 void Avatar::attemptJump( ) {}
272 void Avatar::attemptRotate( AvatarControllerMovement& movement )
{
//TODO: remove the direct references to AvatarCamera
/* float degHoriz = movement.rotationDegHoriz;
float degVert = movement.rotationDegVert;
Ogre::Real timeSlice = movement.timeSlice;*/
// mAccumulatedHorizontalRotation += ( degHoriz * timeSlice );
//if we're moving we must sync the rotation with messages sent to the server
if ( !movement.isMoving && fabs( getAvatarCamera( )->getYaw( ).valueDegrees( ) ) > mThresholdDegreesOfYawForAvatarRotation ) {
// mAvatarNode->setOrientation( movement.cameraOrientation );
mAvatarNode->rotate( Ogre::Vector3::UNIT_Y, getAvatarCamera( )->getYaw( ) );
Ogre::Degree yaw = getAvatarCamera( )->getYaw( );
getAvatarCamera( )->yaw( -yaw );
// mAccumulatedHorizontalRotation = 0;
} else if ( isOkayToSendRotationMovementChangeToServer( ) && ( getAvatarCamera( )->getYaw( ).valueDegrees( ) ) ) {
// rotate the Avatar Node only in X position ( no vertical rotation )
// mAvatarNode->setOrientation( movement.cameraOrientation );
mAvatarNode->rotate( Ogre::Vector3::UNIT_Y, getAvatarCamera( )->getYaw( ) );
Ogre::Degree yaw = getAvatarCamera( )->getYaw( );
getAvatarCamera( )->yaw( -yaw );
// mAvatarNode->rotate( Ogre::Vector3::UNIT_Y, mAccumulatedHorizontalRotation );
// mAccumulatedHorizontalRotation = 0;
}
}
301 bool Avatar::isOkayToSendRotationMovementChangeToServer( )
{
return mTimeSinceLastServerMessage > mMinIntervalOfRotationChanges;
}
307 AvatarCamera* Avatar::getAvatarCamera( ) const
{
return mAvatarController->getAvatarCamera( );
}
312 AvatarEmberEntity* Avatar::getAvatarEmberEntity( )
{
return mErisAvatarEntity;
}
318 void Avatar::setAvatarController( AvatarController* avatarController )
{
mAvatarController = avatarController;
}
323 void Avatar::movedInWorld( )
{
///only snap the avatar to the postiion and orientation sent from the server if we're not moving or if we're not recently changed location
///The main reason when moving is that we don't want to have the avatar snapping back in the case of lag
///However, if we've just recently changed location, we need to also update the orientation to work with the new location.
if ( !mCurrentMovementState.isMoving || mHasChangedLocation )
{
mAvatarNode->setPosition( Atlas2Ogre( mErisAvatarEntity->getPosition( ) ) );
const WFMath::Quaternion& orient = mErisAvatarEntity->getOrientation( );
mAvatarNode->setOrientation( Atlas2Ogre( orient ) );
///we must set this, else ember will think that we've rotated the avatar ourselves and try to send an update to the server
mMovementStateAtLastServerMessage.orientation = mAvatarNode->getOrientation( );
mHasChangedLocation = false;
}
/*
Ember::SoundService* mySoundService = Ember::EmberServices::getSingleton( ).getSoundService( );
{
mySoundService->updateAvatarSourcePosition(
mErisAvatarEntity->getPosition( ),
mErisAvatarEntity>getOrientation( ) );
mySoundService->playAvatarSound( );
}
*/
}
349 void Avatar::avatar_LocationChanged( Eris::Entity* entity )
{
///if we've changed location, we need to update the orientation. This is done on the next onMoved event, which is why we must honour the updated values on next onMoved event, even though we might be moving.
mHasChangedLocation = true;
}
356 void Avatar::createdAvatarEmberEntity( AvatarEmberEntity *emberEntity )
{
Ogre::SceneNode* oldAvatar = mAvatarNode;
///check if the user is of type "creator" and thus an admin
Eris::TypeService* typeService = emberEntity->getErisAvatar( )->getConnection( )->getTypeService( );
if ( emberEntity->getType( )->isA( typeService->getTypeByName( "creator" ) ) ) {
mIsAdmin = true;
} else {
mIsAdmin = false;
}
//mAvatarNode->getParent( )->removeChild( mAvatarNode->getName( ) );
//HACK!!! DEBUG!!
//mAvatarNode->getParent( )->removeChild( mAvatarNode->getName( ) );
//EmberEntity->getSceneNode( )->addChild( mAvatarNode );
// mSceneMgr->getRootSceneNode( )->addChild( mAvatarNode );
//HACK!!! DEBUG!!
mAvatarNode = emberEntity->getSceneNode( );
mAvatarModel = emberEntity->getModel( );
mErisAvatarEntity = emberEntity;
emberEntity->setAvatar( this );
mAvatarController->createAvatarCameras( emberEntity->getSceneNode( ) );
EmberOgre::getSingleton( ).getSceneManager( )->destroySceneNode( oldAvatar->getName( ) );
Input::getSingleton( ).setMovementModeEnabled( true );
mErisAvatarEntity->LocationChanged.connect( sigc::mem_fun( *this, &Avatar::avatar_LocationChanged ) );
}
393 void Avatar::ConfigService_EventChangedConfigItem( const std::string& section, const std::string& key )
{
if ( section == "general" ) {
if ( key == "avatarrotationupdatefrequency" ) {
updateFromConfig( );
}
} else if ( section == "input" ) {
if ( key == "walkspeed" ) {
updateFromConfig( );
}
} else if ( section == "input" ) {
if ( key == "runspeed" ) {
updateFromConfig( );
}
}
}
410 void Avatar::updateFromConfig( )
{
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "general", "avatarrotationupdatefrequency" ) ) {
double frequency = static_cast<double>( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "general", "avatarrotationupdatefrequency" ) );
setMinIntervalOfRotationChanges( static_cast<Ogre::Real>( frequency ) );
}
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "input", "walkspeed" ) ) {
mWalkSpeed = static_cast<double>( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "input", "walkspeed" ) );
}
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "input", "runspeed" ) ) {
mRunSpeed = static_cast<double>( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "input", "runspeed" ) );
}
}
// void Avatar::touch( EmberEntity* entity )
// {
// Ember::EmberServices::getSingletonPtr( )->getServerService( )->touch( entity );
// }
/*
Ogre::Camera* Avatar::getCamera( ) const
{
return mAvatarController->getCamera( );
}
*/
}
1 /*
Avatar.h by Miguel Guzman ( Aglanor )
Copyright ( C ) 2002 Miguel Guzman & The Viewforge Project
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef AVATAR_H
#define AVATAR_H
#include "EmberOgrePrerequisites.h"
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
#include "framework/Singleton.h"
namespace Eris {
32 class Entity;
}
namespace EmberOgre {
namespace Model {
39 class Model;
}
class EmberEntity;
43 class AvatarCamera;
44 class AvatarController;
45 class AvatarEmberEntity;
struct AvatarControllerMovement;
struct AvatarMovementState
{
public:
bool isMoving;
bool isRunning;
Ogre::Vector3 velocity;
Ogre::Quaternion orientation;
};
/**
* This class holds the Avatar. In general it recieves instructions from mainly
* AvatarController to attempt to move or rotate the avatar. After checking
* with the world rules if such a thing is allowed, the world node is manipulated.
* If it's a movement it has to be animated.
*
*/
64 class Avatar :
65 public sigc::trackable,
66 public Ogre::FrameListener
{
68 friend class AvatarController;
69 friend class AvatarEmberEntity;
public:
73 Avatar( );
74 virtual ~Avatar( );
/**
* Gets the avatar camera.
* @return
*/
81 AvatarCamera* getAvatarCamera( ) const;
/**
* Gets the scene node which the avatar is attached to.
* @return
*/
87 inline Ogre::SceneNode* getAvatarSceneNode( ) const;
/**
* Called each frame.
* @param event
* @return
*/
94 virtual bool frameStarted( const Ogre::FrameEvent & event );
/**
* Call this when the Eris::Entity representing the avatar has been created.
* @param EmberEntity
*/
100 void createdAvatarEmberEntity( AvatarEmberEntity *EmberEntity );
/**
* Call this when the avatar entity has moved in the world.
*/
105 void movedInWorld( );
/**
* Called each frame.
* @param movement
*/
112 void updateFrame( AvatarControllerMovement& movement );
/**
* Sets the controller object responsible for controlling the avatar.
* @param avatarController
*/
118 void setAvatarController( AvatarController* avatarController );
/**
* Access for the Eris::Entity which represents the Avatar.
* @return
*/
124 AvatarEmberEntity* getAvatarEmberEntity( );
/**
* sets the minimum interval to wait before sending new rotation changes to the server
* this is not done instantly to prevent swamping of data to the server
* set this lower if you experience too jerky game play
* @param milliseconds
*/
133 void setMinIntervalOfRotationChanges( Ogre::Real milliseconds );
/**
Emitted when an entity is added to the inventory.
*/
138 sigc::signal<void, EmberEntity* > EventAddedEntityToInventory;
/**
Emitted when an entity is removed from the inventory.
*/
143 sigc::signal<void, EmberEntity* > EventRemovedEntityFromInventory;
/**
True if the current user have admin rights, i.e. is a "creator".
*/
148 inline bool isAdmin( ) const;
protected:
/**
* adjust the avatar to the new position in the terrain
* for now this means setting the correct heigth
* accoring to mercator terrain, but it will probably
* be extended to also include stuff as positioning the avatars feet
* right
*/
159 void adjustAvatarToNewPosition( AvatarControllerMovement* movement );
/**
* This method will determine if it's ok to send a small movement change, such as
* a small deviation direction during an already begun movement to the server.
*/
165 bool isOkayToSendRotationMovementChangeToServer( );
/**
Time in milliseconds since we last sent an movement update to the server.
*/
170 Ogre::Real mTimeSinceLastServerMessage;
/**
In milliseconds, the minimum time we must wait between sending updates to the server. Set this higher to avoid spamming the server.
*/
175 Ogre::Real mMinIntervalOfRotationChanges;
/**
In degrees the minimum amount of degrees we can yaw the camera until we need to send an update to the server of our new position.
*/
180 Ogre::Real mThresholdDegreesOfYawForAvatarRotation;
/**
In degrees the accumulated yaw movement since we last sent an update to the server. If this exceeds mThresholdDegreesOfYawForAvatarRotation we need to send an update to the server.
*/
float mAccumulatedHorizontalRotation;
/**
* Attempts to move the avatar in a certain direction
* Note that depending on what the rules allows ( i.e. collision detection,
* character rules etc. ) the outcome of the attempt is uncertain.
*
* The parameter timeSlice denotes the slice of time under which the movement
* shall take place.
*/
195 void attemptMove( AvatarControllerMovement& movement );
/**
* Attempts to rotate the avatar to a certain direction
* Note that depending on what the rules allows ( i.e. collision detection,
* character rules etc. ) the outcome of the attempt is uncertain.
*
* When standing still one can rotate how much one want.
* But when moving, rotation happens in interval
*
*/
206 void attemptRotate( AvatarControllerMovement& movement );
/**
* Attempts to stop the avatar.
* This should work in most cases.
*
*/
214 void attemptStop( );
/**
* Attempt to jump.
*/
219 void attemptJump( );
/**
* Creates the avatar. We'll have to extend this functionality later on to
* allow for different avatars.
*/
226 void createAvatar( );
/**
* Creates and sets up the different cameras.
*/
232 void createAvatarCameras( Ogre::SceneNode* avatarSceneNode );
/**
* How many meters per second the avatar can walk.
* This should be set through some kind of rule checking with the server
* depending on the character. To be done later.
*/
float mWalkSpeed;
/**
* How many meters per second the avatar can run.
* This should be set through some kind of rule checking with the server
* depending on the character. To be done later.
*/
float mRunSpeed;
/**
* The main avatar model
*/
251 Model::Model* mAvatarModel;
/**
* The main avatar scenenode
*/
256 Ogre::SceneNode* mAvatarNode;
/** node for rotating the model for the entity
* if it's not looking in the -Z direction ( default )
* To be removed once we've standarized on models
*/
264 Ogre::SceneNode* mAvatarModelNode;
/**
The Eris::Entity which represents the Avatar.
*/
269 AvatarEmberEntity* mErisAvatarEntity;
/**
* this is used to make sure starts and stops of movement is only sent to the server once
*/
AvatarMovementState mCurrentMovementState;
AvatarMovementState mMovementStateAtBeginningOfMovement; //this is perhaps not needed
AvatarMovementState mMovementStateAtLastServerMessage;
/**
The instance responsible for listening for movement updates and sending those to the server.
*/
281 AvatarController* mAvatarController;
/**
Keep a temporary list of entities that needs to be added to the inventory.
*/
286 std::set<Eris::Entity*> mEntitiesToBeAddedToInventory;
/**
Keep a temporary list of entities that needs to be removed from the inventory.
*/
291 std::set<Eris::Entity*> mEntitiesToBeRemovedFromInventory;
/**
* catch changes to the configuration
* @param section
* @param key
*/
299 void ConfigService_EventChangedConfigItem( const std::string& section, const std::string& key );
/**
* Listen for location changes, since after a location change we need to honour the onMoved updates even if we're in movement mode.
* @param entity
*/
305 void avatar_LocationChanged( Eris::Entity* entity );
/**
* updates values from the configuration
*/
310 void updateFromConfig( );
/**
True if the current user have admin rights, i.e. is a "creator".
*/
315 bool mIsAdmin;
/**
If set to true, the avatar has just changed location, so the next onMoved operation will contain the new orientation and position information for the new location.
*/
320 bool mHasChangedLocation;
}; //End of class declaration
325 bool Avatar::isAdmin( ) const
{
return mIsAdmin;
}
329 Ogre::SceneNode* Avatar::getAvatarSceneNode( ) const
{
return mAvatarNode;
}
}
#endif // ENTITY_LISTENER_H
/*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "AvatarCamera.h"
#include "Avatar.h"
#include "GUIManager.h"
#include "EmberOgre.h"
#include "EmberEntity.h"
// #include "WorldEmberEntity.h"
#include "MathConverter.h"
#include "services/EmberServices.h"
#include "services/config/ConfigService.h"
#ifndef WIN32
#include "services/sound/SoundService.h"
#endif
#include "MousePicker.h"
// #include "jesus/JesusPickerObject.h"
#include "SceneManagers/EmberPagingSceneManager/include/OgrePagingLandScapeRaySceneQuery.h"
#include "framework/Tokeniser.h"
#include "framework/ConsoleBackend.h"
#include "GUIManager.h"
#include "input/Input.h"
#include "IWorldPickListener.h"
#include "framework/osdir.h"
#ifdef __WIN32__
#include <windows.h>
#include <direct.h>
#endif
namespace EmberOgre {
56 Recorder::Recorder( ): mSequence( 0 ), mAccruedTime( 0.0f ), mFramesPerSecond( 20.0f )
{
}
60 void Recorder::startRecording( )
{
Ogre::Root::getSingleton( ).addFrameListener( this );
}
64 void Recorder::stopRecording( )
{
Ogre::Root::getSingleton( ).removeFrameListener( this );
}
69 bool Recorder::frameStarted( const Ogre::FrameEvent& event )
{
mAccruedTime += event.timeSinceLastFrame;
if ( mAccruedTime >= ( 1.0f / mFramesPerSecond ) ) {
mAccruedTime = 0.0f;
std::stringstream filename;
filename << "screenshot_" << mSequence++ << ".tga";
const std::string dir = Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getHomeDirectory( ) + "/recordings/";
try {
//make sure the directory exists
struct stat tagStat;
int ret;
ret = stat( dir.c_str( ), &tagStat );
if ( ret == -1 ) {
#ifdef __WIN32__
mkdir( dir.c_str( ) );
#else
mkdir( dir.c_str( ), S_IRWXU );
#endif
}
} catch ( const std::exception& ex ) {
S_LOG_FAILURE( "Error when creating directory for screenshots. Message: " << std::string( ex.what( ) ) );
stopRecording( );
return true;
}
try {
// take screenshot
EmberOgre::getSingleton( ).getRenderWindow( )->writeContentsToFile( dir + filename.str( ) );
} catch ( const Ogre::Exception& ex ) {
S_LOG_FAILURE( "Could not write screenshot to disc. Message: "<< ex.getFullDescription( ) );
stopRecording( );
return true;
}
}
return true;
}
109 AvatarCamera::AvatarCamera( Ogre::SceneNode* avatarNode, Ogre::SceneManager* sceneManager, Ogre::RenderWindow* window, GUIManager* guiManager, Ogre::Camera* camera ) :
SetCameraDistance( "setcameradistance", this, "Set the distance of the camera." ),
ToggleRendermode( "toggle_rendermode", this, "Toggle between wireframe and solid render modes." ),
ToggleFullscreen( "toggle_fullscreen", this, "Switch between windowed and full screen mode." ),
Screenshot( "screenshot", this, "Take a screenshot and write to disk." ),
Record( "+record", this, "Record to disk." ),
mInvertCamera( false ),
mGUIManager( guiManager ),
mCamera( camera ),
mAvatarNode( 0 ),
mSceneManager( sceneManager ),
mDegreeOfPitchPerSecond( 50 ),
mDegreeOfYawPerSecond( 50 ),
degreePitch( 0 ),
degreeYaw( 0 ),
mWindow( window ),
mViewPort( 0 ),
mClosestPickingDistance( 10000 ),
mLastPosition( Ogre::Vector3::ZERO ),
mAdjustTerrainRaySceneQuery( 0 ),
mCameraRaySceneQuery( 0 ),
mIsAdjustedToTerrain( true )
// mLastOrientationOfTheCamera( avatar->getOrientation( ) )
{
createNodesForCamera( );
createViewPort( );
setAvatarNode( avatarNode );
/// Register this as a frame listener
Ogre::Root::getSingleton( ).addFrameListener( this );
if ( mGUIManager ) {
mGUIManager->getInput( ).EventMouseMoved.connect( sigc::mem_fun( *this, &AvatarCamera::Input_MouseMoved ) );
}
Ember::EmberServices::getSingletonPtr( )->getConfigService( )->EventChangedConfigItem.connect( sigc::mem_fun( *this, &AvatarCamera::ConfigService_EventChangedConfigItem ) );
updateValuesFromConfig( );
createRayQueries( );
}
AvatarCamera::~AvatarCamera( )
{
Ogre::Root::getSingleton( ).removeFrameListener( this );
EmberOgre::getSingleton( ).getSceneManager( )->destroyQuery( mAdjustTerrainRaySceneQuery );
EmberOgre::getSingleton( ).getSceneManager( )->destroyQuery( mCameraRaySceneQuery );
}
void AvatarCamera::createRayQueries( )
{
mAdjustTerrainRaySceneQuery = EmberOgre::getSingletonPtr( )->getSceneManager( )->createRayQuery( mAdjustTerrainRay, Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK );
///only test for terrain
mAdjustTerrainRaySceneQuery->setWorldFragmentType( Ogre::SceneQuery::WFT_SINGLE_INTERSECTION );
mAdjustTerrainRaySceneQuery->setSortByDistance( true );
mAdjustTerrainRaySceneQuery->setQueryTypeMask( Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK );
unsigned long queryMask = Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK;
queryMask |= MousePicker::CM_AVATAR;
queryMask |= MousePicker::CM_ENTITY;
queryMask |= MousePicker::CM_NATURE;
queryMask |= MousePicker::CM_UNDEFINED;
// queryMask |= Ogre::RSQ_FirstTerrain;
mCameraRaySceneQuery = mSceneManager->createRayQuery( Ogre::Ray( ), queryMask );
mCameraRaySceneQuery->setWorldFragmentType( Ogre::SceneQuery::WFT_SINGLE_INTERSECTION );
mCameraRaySceneQuery->setSortByDistance( true );
}
void AvatarCamera::createNodesForCamera( )
{
mAvatarCameraRootNode = mSceneManager->createSceneNode( "AvatarCameraRootNode" );
//we need to adjust for the height of the avatar mesh
mAvatarCameraRootNode->setPosition( Ogre::Vector3( 0, 2, 0 ) );
//rotate to sync with WF world
mAvatarCameraRootNode->rotate( Ogre::Vector3::UNIT_Y, ( Ogre::Degree )-90 );
mAvatarCameraPitchNode = mAvatarCameraRootNode->createChildSceneNode( "AvatarCameraPitchNode" );
mAvatarCameraPitchNode->setPosition( Ogre::Vector3( 0, 0, 0 ) );
mAvatarCameraNode = mAvatarCameraPitchNode->createChildSceneNode( "AvatarCameraNode" );
setCameraDistance( 10 );
// mCamera = mSceneManager->createCamera( "AvatarCamera" );
mAvatarCameraNode->attachObject( mCamera );
// Look to the Avatar's head
//mAvatar3pCamera->setAutoTracking( true, mAvatar1pCameraNode );
mCamera->setNearClipDistance( 0.5 );
///set the far clip distance high to make sure that the sky is completely shown
if ( Ogre::Root::getSingleton( ).getRenderSystem( )->getCapabilities( )->hasCapability( Ogre::RSC_INFINITE_FAR_PLANE ) )
{
/* //NOTE: this won't currently work with the sky
mCamera->setFarClipDistance( 0 );*/
mCamera->setFarClipDistance( 10000 );
} else {
mCamera->setFarClipDistance( 10000 );
}
//create the nodes for the camera
setMode( MODE_THIRD_PERSON );
// createViewPort( );
}
void AvatarCamera::setMode( Mode mode )
{
mMode = mode;
/* if ( mMode == MODE_THIRD_PERSON ) {
mCamera->setAutoTracking( true, mAvatarCameraRootNode );
} else {
mCamera->setAutoTracking( false );
}*/
}
const Ogre::Quaternion& AvatarCamera::getOrientation( bool onlyHorizontal ) const {
if ( !onlyHorizontal ) {
return getCamera( )->getDerivedOrientation( );
} else {
static Ogre::Quaternion quat;
quat = getCamera( )->getDerivedOrientation( );
quat.x = 0;
quat.z = 0;
return quat;
}
}
const Ogre::Vector3& AvatarCamera::getPosition( ) const
{
return mCamera->getDerivedPosition( );
}
void AvatarCamera::attach( Ogre::SceneNode* toNode ) {
mIsAttached = true;
assert( mAvatarCameraRootNode );
if ( mAvatarCameraRootNode->getParent( ) ) {
mAvatarCameraRootNode->getParent( )->removeChild( mAvatarCameraRootNode->getName( ) );
}
toNode->addChild( mAvatarCameraRootNode );
setCameraDistance( 10 );
mAvatarCameraNode->setOrientation( Ogre::Quaternion::IDENTITY );
mAvatarCameraNode->_update( true, true );
std::stringstream ss;
ss << "Attached camera to node: " << toNode->getName( ) <<". New position: " << mCamera->getWorldPosition( ) << " New orientation: " << mCamera->getWorldOrientation( );
S_LOG_VERBOSE( ss.str( ) );
}
void AvatarCamera::enableCompositor( const std::string& compositorName, bool enable )
{
if ( std::find( mLoadedCompositors.begin( ), mLoadedCompositors.end( ), compositorName ) == mLoadedCompositors.end( ) ) {
Ogre::CompositorManager::getSingleton( ).addCompositor( mWindow->getViewport( 0 ), compositorName );
}
Ogre::CompositorManager::getSingleton( ).setCompositorEnabled( mWindow->getViewport( 0 ), compositorName, enable );
}
void AvatarCamera::createViewPort( )
{
// Ogre::CompositorManager::getSingleton( ).addCompositor( mWindow->getViewport( 0 ), "Bloom" );
// Ogre::CompositorManager::getSingleton( ).setCompositorEnabled( mWindow->getViewport( 0 ), "Bloom", true );
// assert( mCamera );
// assert( !mViewPort );
// // Create 1st person viewport, entire window
// mViewPort = mWindow->addViewport( mCamera );
// mViewPort->setBackgroundColour( Ogre::ColourValue( 0, 0, 0 ) );
// mCamera->setAspectRatio(
// Ogre::Real( mViewPort->getActualWidth( ) ) / Ogre::Real( mViewPort->getActualHeight( ) ) );
}
void AvatarCamera::toggleRenderMode( )
{
S_LOG_INFO( "Switching render mode." );
if ( mCamera->getPolygonMode( ) == Ogre::PM_SOLID ) {
mCamera->setPolygonMode( Ogre::PM_WIREFRAME );
} else {
mCamera->setPolygonMode( Ogre::PM_SOLID );
}
}
void AvatarCamera::setAvatarNode( Ogre::SceneNode* sceneNode )
{
mAvatarNode = sceneNode;
attach( mAvatarNode );
}
void AvatarCamera::setCameraDistance( Ogre::Real distance )
{
mWantedCameraDistance = distance;
_setCameraDistance( distance );
}
void AvatarCamera::_setCameraDistance( Ogre::Real distance )
{
mCurrentCameraDistance = distance;
Ogre::Vector3 pos( 0, 0, distance );
mAvatarCameraNode->setPosition( pos );
EventChangedCameraDistance.emit( distance );
}
void AvatarCamera::pitch( Ogre::Degree degrees )
{
if ( mInvertCamera ) {
degrees -= degrees * 2;
}
if ( mMode == MODE_THIRD_PERSON ) {
degreePitch += degrees;
mAvatarCameraPitchNode->pitch( degrees );
} else {
mAvatarCameraNode->pitch( degrees );
}
}
void AvatarCamera::yaw( Ogre::Degree degrees )
{
if ( mMode == MODE_THIRD_PERSON ) {
degreeYaw += degrees;
mAvatarCameraRootNode->yaw( degrees );
mAvatarCameraRootNode->needUpdate( );
// Ogre::Quaternion q = mAvatarCameraRootNode->_getDerivedOrientation( );
} else {
mAvatarCameraNode->yaw( degrees );
}
}
void AvatarCamera::Input_MouseMoved( const MouseMotion& motion, Input::InputMode mode )
/*( int xPosition, int yPosition, Ogre::Real xRelativeMovement, Ogre::Real yRelativeMovement, Ogre::Real timeSinceLastMovement )*/
{
if ( mode == Input::IM_MOVEMENT ) {
Ogre::Degree diffX( mDegreeOfYawPerSecond * motion.xRelativeMovement );
Ogre::Degree diffY( mDegreeOfPitchPerSecond * motion.yRelativeMovement );
if ( diffX.valueDegrees( ) ) {
this->yaw( diffX );
// this->yaw( diffX * e->timeSinceLastFrame );
}
if ( diffY.valueDegrees( ) ) {
this->pitch( diffY );
// this->pitch( diffY * e->timeSinceLastFrame );
}
if ( diffY.valueDegrees( ) || diffX.valueDegrees( ) ) {
MovedCamera.emit( mCamera );
}
}
}
void AvatarCamera::pickInWorld( Ogre::Real mouseX, Ogre::Real mouseY, const MousePickerArgs& mousePickerArgs )
{
S_LOG_INFO( "Trying to pick an entity at mouse coords: " << Ogre::StringConverter::toString( mouseX ) << ":" << Ogre::StringConverter::toString( mouseY ) << "." );
/// Start a new ray query
Ogre::Ray cameraRay = getCamera( )->getCameraToViewportRay( mouseX, mouseY );
mCameraRaySceneQuery->setRay( cameraRay );
mCameraRaySceneQuery->execute( );
///now check the entity picking
Ogre::RaySceneQueryResult& queryResult = mCameraRaySceneQuery->getLastResults( );
bool continuePicking = true;
for ( WorldPickListenersStore::iterator I = mPickListeners.begin( ); I != mPickListeners.end( ); ++I ) {
( *I )->initializePickingContext( );
}
Ogre::RaySceneQueryResult::iterator rayIterator = queryResult.begin( );
Ogre::RaySceneQueryResult::iterator rayIterator_end = queryResult.end( );
if ( rayIterator != rayIterator_end ) {
for ( ; rayIterator != rayIterator_end && continuePicking; rayIterator++ ) {
for ( WorldPickListenersStore::iterator I = mPickListeners.begin( ); I != mPickListeners.end( ); ++I ) {
( *I )->processPickResult( continuePicking, *rayIterator, cameraRay, mousePickerArgs );
if ( !continuePicking ) {
break;
}
}
}
}
for ( WorldPickListenersStore::iterator I = mPickListeners.begin( ); I != mPickListeners.end( ); ++I ) {
( *I )->endPickingContext( mousePickerArgs );
}
}
bool AvatarCamera::worldToScreen( const Ogre::Vector3& worldPos, Ogre::Vector3& screenPos )
{
Ogre::Vector3 hcsPosition = mCamera->getProjectionMatrix( ) * ( mCamera->getViewMatrix( ) * worldPos );
if ( ( hcsPosition.x < -1.0f ) ||
( hcsPosition.x > 1.0f ) ||
( hcsPosition.y < -1.0f ) ||
( hcsPosition.y > 1.0f ) )
return false;
screenPos.x = ( hcsPosition.x + 1 ) * 0.5;
screenPos.y = ( -hcsPosition.y + 1 ) * 0.5;
return true;
}
void AvatarCamera::setClosestPickingDistance( Ogre::Real distance )
{
mClosestPickingDistance = distance;
}
Ogre::Real AvatarCamera::getClosestPickingDistance( )
{
return mClosestPickingDistance;
}
bool AvatarCamera::adjustForTerrain( )
{
/// We will shoot a ray from the camera base node to the camera. If it hits anything on the way we know that there's something between the camera and the avatar and we'll position the camera closer to the avatar. Thus we'll avoid having the camera dip below the terrain
///For now we'll only check against the terrain
const Ogre::Vector3 direction( -mCamera->getDerivedDirection( ) );
///If the direction if pointing straight upwards we'll end up in an infinite loop in the ray query
if ( direction.z != 0 ) {
mAdjustTerrainRay.setDirection( direction );
mAdjustTerrainRay.setOrigin( mAvatarCameraRootNode->getWorldPosition( ) );
mAdjustTerrainRaySceneQuery->setRay( mAdjustTerrainRay );
mAdjustTerrainRaySceneQuery->execute( );
Ogre::RaySceneQueryResult queryResult = mAdjustTerrainRaySceneQuery->getLastResults( );
Ogre::RaySceneQueryResult::iterator rayIterator = queryResult.begin( );
for ( ; rayIterator != queryResult.end( ); ++rayIterator ) {
Ogre::RaySceneQueryResultEntry& entry = *rayIterator;
if ( entry.worldFragment ) {
Ogre::Vector3 position = entry.worldFragment->singleIntersection;
Ogre::Real distance = mAvatarCameraRootNode->getWorldPosition( ).distance( position );
if ( distance < mWantedCameraDistance ) {
_setCameraDistance( distance - 0.1 );
} else {
if ( mWantedCameraDistance != mCurrentCameraDistance ) {
_setCameraDistance( mWantedCameraDistance );
}
}
break;
}
}
}
/* Ogre::RaySceneQuery *raySceneQueryHeight = EmberOgre::getSingletonPtr( )->getSceneManager( )->createRayQuery( Ogre::Ray( mCamera->getDerivedPosition( ), Ogre::Vector3::NEGATIVE_UNIT_Y ), Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK );
raySceneQueryHeight->execute( );
//first check the terrain picking
Ogre::RaySceneQueryResult queryResult = raySceneQueryHeight->getLastResults( );
if ( queryResult.begin( ) != queryResult.end( ) ) {
Ogre::Vector3 position = queryResult.begin( )->worldFragment->singleIntersection;
Ogre::Real terrainHeight = position.y;
//pad it a little
//terrainHeight += 0.4;
Ogre::Real cameraHeight = mCamera->getDerivedPosition( ).y;
Ogre::Real cameraNodeHeight = mAvatarCameraNode->getWorldPosition( ).y;
if ( terrainHeight > cameraHeight ) {
mCamera->move( mCamera->getDerivedOrientation( ).Inverse( ) * Ogre::Vector3( 0, terrainHeight - cameraHeight, 0 ) );
// mCamera->lookAt( mAvatarCameraRootNode->getPosition( ) );
} else if ( cameraHeight != cameraNodeHeight ) {
Ogre::Real newHeight = std::max<Ogre::Real>( terrainHeight, cameraNodeHeight );
mCamera->move( Ogre::Vector3( 0, newHeight - cameraHeight, 0 ) );
mCamera->lookAt( mAvatarCameraRootNode->getWorldPosition( ) );
}
}*/
return true;
}
void AvatarCamera::runCommand( const std::string &command, const std::string &args )
{
if( Screenshot == command ) {
//just take a screen shot
takeScreenshot( );
} else if( SetCameraDistance == command )
{
Ember::Tokeniser tokeniser;
tokeniser.initTokens( args );
std::string distance = tokeniser.nextToken( );
if ( distance != "" ) {
float fDistance = Ogre::StringConverter::parseReal( distance );
setCameraDistance( fDistance );
}
} else if ( ToggleFullscreen == command ){
SDL_WM_ToggleFullScreen( SDL_GetVideoSurface( ) );
} else if ( ToggleRendermode == command ) {
toggleRenderMode( );
} else if ( Record == command ) {
mRecorder.startRecording( );
} else if ( Record.getInverseCommand( ) == command ) {
mRecorder.stopRecording( );
}
}
void AvatarCamera::updateValuesFromConfig( )
{
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "input", "invertcamera" ) ) {
mInvertCamera = static_cast<bool>( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "input", "invertcamera" ) );
}
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "input", "cameradegreespersecond" ) ) {
mDegreeOfPitchPerSecond = mDegreeOfYawPerSecond = ( double )Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "input", "cameradegreespersecond" );
}
if ( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->itemExists( "input", "adjusttoterrain" ) ) {
mIsAdjustedToTerrain = static_cast<bool>( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getValue( "input", "adjusttoterrain" ) );
}
}
void AvatarCamera::ConfigService_EventChangedConfigItem( const std::string& section, const std::string& key )
{
if ( section == "input" ) {
if ( key == "invertcamera" || key == "cameradegreespersecond" || key == "adjusttoterrain" ) {
updateValuesFromConfig( );
}
}
}
bool AvatarCamera::frameStarted( const Ogre::FrameEvent& event )
{
if ( mIsAdjustedToTerrain ) {
if ( mCamera->getDerivedPosition( ) != mLastPosition ) {
adjustForTerrain( );
}
}
mLastPosition = mCamera->getDerivedPosition( );
// #ifndef WIN32
// Ember::SoundService* mySoundService = Ember::EmberServices::getSingleton( ).getSoundService( );
// {
// mySoundService->updateListenerPosition(
// Ogre2Atlas( mCamera->getPosition( ) ),
// Ogre2Atlas( mCamera->getOrientation( ) ) );
// }
// #endif
return true;
}
void AvatarCamera::pushWorldPickListener( IWorldPickListener* worldPickListener )
{
mPickListeners.push_front( worldPickListener );
}
const std::string AvatarCamera::_takeScreenshot( )
{
// retrieve current time
time_t rawtime;
struct tm* timeinfo;
time( &rawtime );
timeinfo = localtime( &rawtime );
// construct filename string
// padding with 0 for single-digit values
std::stringstream filename;
filename << "screenshot_" << ( ( *timeinfo ).tm_year + 1900 ); // 1900 is year "0"
int month = ( ( *timeinfo ).tm_mon + 1 ); // January is month "0"
if( month <= 9 )
{
filename << "0";
}
filename << month;
int day = ( *timeinfo ).tm_mday;
if( day <= 9 )
{
filename << "0";
}
filename << day << "_";
int hour = ( *timeinfo ).tm_hour;
if( hour <= 9 )
{
filename << "0";
}
filename << hour;
int min = ( *timeinfo ).tm_min;
if( min <= 9 )
{
filename << "0";
}
filename << min;
int sec = ( *timeinfo ).tm_sec;
if( sec <= 9 )
{
filename << "0";
}
filename << sec << ".jpg";
const std::string dir = Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getHomeDirectory( ) + "/screenshots/";
try {
//make sure the directory exists
oslink::directory osdir( dir );
if ( !osdir.isExisting( ) ) {
#ifdef __WIN32__
mkdir( dir.c_str( ) );
#else
mkdir( dir.c_str( ), S_IRWXU );
#endif
}
} catch ( const std::exception& ex ) {
S_LOG_FAILURE( "Error when creating directory for screenshots. Message: " << std::string( ex.what( ) ) );
throw Ember::Exception( "Error when saving screenshot. Message: " + std::string( ex.what( ) ) );
}
try {
// take screenshot
mWindow->writeContentsToFile( dir + filename.str( ) );
} catch ( const Ogre::Exception& ex ) {
S_LOG_FAILURE( "Could not write screenshot to disc. Message: "<< ex.getFullDescription( ) );
throw Ember::Exception( "Error when saving screenshot. Message: " + ex.getDescription( ) );
}
return dir + filename.str( );
}
void AvatarCamera::takeScreenshot( )
{
try {
const std::string& result = _takeScreenshot( );
S_LOG_INFO( result );
Ember::ConsoleBackend::getMainConsole( )->pushMessage( "Wrote image: " + result );
} catch ( const Ember::Exception& ex ) {
Ember::ConsoleBackend::getMainConsole( )->pushMessage( "Error when saving screenshot: " + ex.getError( ) );
}
}
}
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* An instance of this is a player controlled camera fastened to the Avatar.
* It should be possible to subclass this in order to provide different behaviour
*/
#ifndef AVATARCAMERA_H
#define AVATARCAMERA_H
#include "EmberOgrePrerequisites.h"
#include <sigc++/trackable.h>
#include "framework/ConsoleObject.h"
#include "input/Input.h"
#include <stack>
namespace EmberOgre {
41 class Avatar;
42 class InputManager;
43 class GUIManager;
44 class EmberEntity;
struct MouseMotion;
struct EntityPickResult;
47 class IWorldPickListener;
struct MousePickerArgs;
50 class Recorder :public Ogre::FrameListener
{
public:
53 Recorder( );
54 void startRecording( );
55 void stopRecording( );
/**
* Methods from Ogre::FrameListener
*/
59 bool frameStarted( const Ogre::FrameEvent& event );
private:
int mSequence;
float mAccruedTime;
float mFramesPerSecond;
};
67 class AvatarCamera
:
69 public sigc::trackable,
70 public Ember::ConsoleObject,
71 public Ogre::FrameListener
{
public:
enum Mode {
MODE_THIRD_PERSON = 1,
MODE_FIRST_PERSON = 2
};
80 AvatarCamera( Ogre::SceneNode* avatarNode, Ogre::SceneManager* sceneManager, Ogre::RenderWindow* window, GUIManager* guiManager, Ogre::Camera* camera );
81 virtual ~AvatarCamera( );
/**
* Pitches the camera the supplied degrees
*/
86 virtual void pitch( Ogre::Degree degrees );
/**
* Yaws the camera the supplied degrees
*/
91 virtual void yaw( Ogre::Degree degrees );
/**
* returns the current degrees of pitch from the cameras initial position
*/
96 inline const Ogre::Degree& getPitch( ) const;
/**
* returns the current degrees of yaw from the cameras initial position
*/
101 inline const Ogre::Degree& getYaw( ) const;
/**
* returns a pointer to the Ogre::Camera instance
*/
106 inline Ogre::Camera* getCamera( );
107 inline Ogre::Camera* getCamera( ) const;
/**
* Returns the current camera orientation in the world
*/
112 virtual const Ogre::Quaternion& getOrientation( bool onlyHorizontal = true ) const;
/**
* Returns the position of the camera in the world.
* @return
*/
119 const Ogre::Vector3& getPosition( ) const;
122 void setMode( Mode mode );
/**
* sets the node to which the camera is attached
*/
127 virtual void setAvatarNode( Ogre::SceneNode* sceneNode );
/**
* emitted when the camra moves
*/
132 sigc::signal<void, Ogre::Camera*> MovedCamera;
/**
* emitted when the distance between the camera and the avatar has changed
* @param Ogre::Real the new distance
*/
138 sigc::signal<void, Ogre::Real> EventChangedCameraDistance;
// int xPosition, int yPosition, Ogre::Real xRelativeMovement, Ogre::Real yRelativeMovement, Ogre::Real timeSinceLastMovement );
// void mouseMoved ( Ogre::MouseEvent *e );
// void mouseDragged ( Ogre::MouseEvent *e ) {};
145 void pickInWorld( Ogre::Real mouseX, Ogre::Real mouseY, const MousePickerArgs& args );
// EntityPickResult pickAnEntity( Ogre::Real mouseX, Ogre::Real mouseY );
// std::vector<Ogre::RaySceneQueryResultEntry> AvatarCamera::pickObject( Ogre::Real mouseX, Ogre::Real mouseY, std::vector<Ogre::UserDefinedObject*> exclude, unsigned long querymask );
150 void setClosestPickingDistance( Ogre::Real distance );
151 Ogre::Real getClosestPickingDistance( );
/**
* returns true if the worldPos is on screen, putting the screen pos into the x & y of the second Vector3
* returns false if the worldPos is off screen
* @param worldPos
* @param screenPos
* @return
*/
160 bool worldToScreen( const Ogre::Vector3& worldPos, Ogre::Vector3& screenPos );
/**
* Attaches the camera to the specified scene node.
* @param toNode
*/
166 void attach( Ogre::SceneNode* toNode );
/**
* Adjusts the camera for the terrain, so it doesn't dip below it.
* @return
*/
172 bool adjustForTerrain( );
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
180 virtual void runCommand( const std::string &command, const std::string &args );
/**
* Sets the distance from the camera to the avatar.
* @param distance the new distance
*/
187 void setCameraDistance( Ogre::Real distance );
/**
* Methods from Ogre::FrameListener
*/
192 bool frameStarted( const Ogre::FrameEvent& event );
//bool frameEnded( const Ogre::FrameEvent& event );
/**
* Enables and disables a compositor by name.
* @param compositorName
* @param enable
*/
200 void enableCompositor( const std::string& compositorName, bool enable );
/**
* Adds a new world pick listener to the queue of listeners.
* @param worldPickListener
*/
207 void pushWorldPickListener( IWorldPickListener* worldPickListener );
209 const Ember::ConsoleCommandWrapper SetCameraDistance;
210 const Ember::ConsoleCommandWrapper ToggleRendermode;
211 const Ember::ConsoleCommandWrapper ToggleFullscreen;
212 const Ember::ConsoleCommandWrapper Screenshot;
213 const Ember::ConsoleCommandWrapper Record;
/**
Toggles between wireframe and solid render mode.
*/
218 void toggleRenderMode( );
/**
* takes a screen shot and writes it to disk
*/
223 void takeScreenshot( );
protected:
typedef std::deque<IWorldPickListener*> WorldPickListenersStore;
228 WorldPickListenersStore mPickListeners;
typedef std::vector<std::string> CompositorNameStore;
232 Recorder mRecorder;
234 CompositorNameStore mLoadedCompositors;
Mode mMode;
238 bool mIsAttached;
/**
If true, the camera is inverted in the y axis.
*/
243 bool mInvertCamera;
/**
Creates the rays needed for mouse picking and camera adjustment.
*/
248 void createRayQueries( );
/**
* creates all nodes needed for the camera
*/
254 void createNodesForCamera( );
256 const std::string _takeScreenshot( );
258 void createViewPort( );
259 GUIManager* mGUIManager;
262 Ogre::Camera* mCamera;
263 Ogre::SceneNode* mAvatarNode;
264 Ogre::SceneManager* mSceneManager;
//Ogre::Quaternion mLastOrientationOfTheCamera;
267 Ogre::SceneNode* mAvatarCameraRootNode;
268 Ogre::SceneNode* mAvatarCameraPitchNode;
269 Ogre::SceneNode* mAvatarCameraNode;
271 Ogre::Degree mDegreeOfPitchPerSecond;
272 Ogre::Degree mDegreeOfYawPerSecond;
274 Ogre::Degree degreePitch;
275 Ogre::Degree degreeYaw;
276 Ogre::RenderWindow* mWindow;
277 Ogre::Viewport* mViewPort;
//in meters how far we can pick objects
280 Ogre::Real mClosestPickingDistance;
282 Ogre::Vector3 mLastPosition;
283 Ogre::Real mWantedCameraDistance, mCurrentCameraDistance;
285 Ogre::RaySceneQuery *mAdjustTerrainRaySceneQuery, *mCameraRaySceneQuery;
286 Ogre::Ray mAdjustTerrainRay;
288 bool mIsAdjustedToTerrain;
290 void Input_MouseMoved( const MouseMotion& motion, Input::InputMode mode );
292 void ConfigService_EventChangedConfigItem( const std::string& section, const std::string& key );
294 void updateValuesFromConfig( );
/**
* Internal method for setting the camera distance.
* @param distance the new distance
*/
300 void _setCameraDistance( Ogre::Real distance );
};
///inline implementations
307 const Ogre::Degree& AvatarCamera::getPitch( ) const
{
return degreePitch;
}
312 const Ogre::Degree& AvatarCamera::getYaw( ) const
{
return degreeYaw;
}
317 Ogre::Camera* AvatarCamera::getCamera( ) {
return mCamera;
}
320 Ogre::Camera* AvatarCamera::getCamera( ) const {
return mCamera;
}
326 class ICameraMount
{
328 virtual ~ICameraMount( ) {};
/**
* Pitches the camera the supplied degrees
*/
333 virtual void pitch( Ogre::Degree degrees ) = 0;
/**
* Yaws the camera the supplied degrees
*/
338 virtual void yaw( Ogre::Degree degrees ) = 0;
/**
* returns the current degrees of pitch from the cameras initial position
*/
343 virtual const Ogre::Degree& getPitch( ) const = 0;
/**
* returns the current degrees of yaw from the cameras initial position
*/
348 virtual const Ogre::Degree& getYaw( ) const = 0;
/**
* Returns the current camera orientation in the world
*/
353 virtual const Ogre::Quaternion& getOrientation( bool onlyHorizontal = true ) const = 0;
/**
* Returns the position of the camera in the world.
* @return
*/
359 virtual const Ogre::Vector3& getPosition( ) const = 0;
361 void setMode( AvatarCamera::Mode mode );
/**
* sets the node to which the camera is attached
*/
366 virtual void setAvatarNode( Ogre::SceneNode* sceneNode );
};
370 class MainCamera
{
372 virtual ~MainCamera( ) {}
/**
* returns a pointer to the Ogre::Camera instance
*/
377 inline Ogre::Camera* getCamera( );
378 inline Ogre::Camera* getCamera( ) const;
/**
* emitted when the camra moves
*/
383 sigc::signal<void, Ogre::Camera*> MovedCamera;
386 void pickInWorld( Ogre::Real mouseX, Ogre::Real mouseY, const MousePickerArgs& args );
388 void setClosestPickingDistance( Ogre::Real distance );
389 Ogre::Real getClosestPickingDistance( );
/**
* returns true if the worldPos is on screen, putting the screen pos into the x & y of the second Vector3
* returns false if the worldPos is off screen
* @param worldPos
* @param screenPos
* @return
*/
398 bool worldToScreen( const Ogre::Vector3& worldPos, Ogre::Vector3& screenPos );
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
405 virtual void runCommand( const std::string &command, const std::string &args );
/**
* Methods from Ogre::FrameListener
*/
410 bool frameStarted( const Ogre::FrameEvent& event );
/**
* Enables and disables a compositor by name.
* @param compositorName
* @param enable
*/
417 void enableCompositor( const std::string& compositorName, bool enable );
/**
* Adds a new world pick listener to the queue of listeners.
* @param worldPickListener
*/
424 void pushWorldPickListener( IWorldPickListener* worldPickListener );
426 const Ember::ConsoleCommandWrapper ToggleRendermode;
427 const Ember::ConsoleCommandWrapper ToggleFullscreen;
428 const Ember::ConsoleCommandWrapper Screenshot;
429 const Ember::ConsoleCommandWrapper Record;
/**
Toggles between wireframe and solid render mode.
*/
434 void toggleRenderMode( );
/**
* takes a screen shot and writes it to disk
*/
439 void takeScreenshot( );
};
443 class AvatarCameraMount : ICameraMount
{
/**
* emitted when the distance between the camera and the avatar has changed
* @param Ogre::Real the new distance
*/
449 sigc::signal<void, Ogre::Real> EventChangedCameraDistance;
/**
* Sets the distance from the camera to the avatar.
* @param distance the new distance
*/
455 void setCameraDistance( Ogre::Real distance );
457 const Ember::ConsoleCommandWrapper SetCameraDistance;
};
461 class FreeFlyingMount : ICameraMount
{
};
}
#endif // AVATARCAMERA_H
/*
Copyright ( C ) 2004 Erik Hjortsberg
some parts Copyright ( C ) 2004 bad_camel at Ogre3d forums
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "AvatarController.h"
#include "EmberEntity.h"
#include "EmberPhysicalEntity.h"
#include "AvatarEmberEntity.h"
#include "AvatarCamera.h"
#include "GUIManager.h"
#include "Avatar.h"
#include "EmberOgre.h"
// #include "SceneManagers/EmberPagingSceneManager/include/EmberPagingSceneManager.h"
#include "terrain/TerrainGenerator.h"
#include "terrain/ISceneManagerAdapter.h"
#include "input/Input.h"
#include "framework/Tokeniser.h"
#include "MathConverter.h"
#include "services/EmberServices.h"
#include "services/server/ServerService.h"
using namespace Ogre;
namespace EmberOgre {
AvatarControllerMovement::AvatarControllerMovement( ) :
rotationDegHoriz( 0 ),
rotationDegVert( 0 ),
timeSlice( 0 ),
movementDirection( Ogre::Vector3::ZERO ),
mode( AvatarMovementMode::MM_WALK ),
isMoving( false )
{
}
61 AvatarControllerInputListener::AvatarControllerInputListener( AvatarController& controller )
: mController( controller )
{
Input::getSingleton( ).EventMouseButtonPressed.connect( sigc::mem_fun( *this, &AvatarControllerInputListener::input_MouseButtonPressed ) );
Input::getSingleton( ).EventMouseButtonReleased.connect( sigc::mem_fun( *this, &AvatarControllerInputListener::input_MouseButtonReleased ) );
}
69 void AvatarControllerInputListener::input_MouseButtonPressed( Input::MouseButton button, Input::InputMode mode )
{
if ( mode == Input::IM_MOVEMENT && button == Input::MouseButtonLeft ) {
mController.mMovementDirection.x = 1;
}
}
76 void AvatarControllerInputListener::input_MouseButtonReleased( Input::MouseButton button, Input::InputMode mode )
{
if ( mode == Input::IM_MOVEMENT && button == Input::MouseButtonLeft ) {
mController.mMovementDirection.x = 0;
}
}
83 AvatarController::AvatarController( Avatar* avatar, Ogre::RenderWindow* window, GUIManager* guiManager, Ogre::Camera* camera )
: RunToggle( "+run", this, "Toggle running mode." )
85 , ToggleCameraAttached( "toggle_cameraattached", this, "Toggle between the camera being attached to the avatar and free flying." )
, CharacterMoveForward( "+character_move_forward", this, "Move the avatar forward." )
, CharacterMoveBackward( "+character_move_backward", this, "Move the avatar backward." )
, CharacterMoveDownwards( "+character_move_downwards", this, "Move the avatar downwards." )
, CharacterMoveUpwards( "+character_move_upwards", this, "Move the avatar upwards." )
, CharacterStrafeLeft( "+character_strafe_left", this, "Strafe left." )
, CharacterStrafeRight( "+character_strafe_right", this, "Strafe right." )
/*, CharacterRotateLeft( "+character_rotate_left", this, "Rotate left." )
, CharacterRotateRight( "+character_rotate_right", this, "Rotate right." )*/
, MoveCameraTo( "movecamerato", this, "Moves the camera to a point." )
, mMovementCommandMapper( "movement", "key_bindings_movement" )
, mWindow( window )
, mGUIManager( guiManager )
, mAvatarCamera( 0 )
, mCamera( camera )
, mEntityUnderCursor( 0 )
, mSelectedEntity( 0 )
, mFreeFlyingCameraNode( 0 )
, mIsRunning( false )
, mMovementDirection( Ogre::Vector3::ZERO )
, mDecalObject( 0 )
, mDecalNode( 0 )
, mControllerInputListener( *this )
{
mMovementCommandMapper.restrictToInputMode( Input::IM_MOVEMENT );
setAvatar( avatar );
mAvatar->setAvatarController( this );
Ogre::Root::getSingleton( ).addFrameListener( this );
mFreeFlyingCameraNode = EmberOgre::getSingleton( ).getSceneManager( )->getRootSceneNode( )->createChildSceneNode( );
mFreeFlyingCameraNode->setPosition( 0, 30, 0 );
detachCamera( );
mMovementCommandMapper.bindToInput( Input::getSingleton( ) );
GUIManager::getSingleton( ).getEntityPickListener( )->EventPickedEntity.connect( sigc::mem_fun( *this, &AvatarController::entityPicker_PickedEntity ) );
}
130 AvatarController::~AvatarController( )
{
Ogre::Root::getSingleton( ).removeFrameListener( this );
delete mAvatarCamera;
}
136 void AvatarController::createAvatarCameras( Ogre::SceneNode* avatarSceneNode )
{
if ( mAvatarCamera == 0 ) {
mAvatarCamera = new AvatarCamera( avatarSceneNode, EmberOgre::getSingletonPtr( )->getSceneManager( ), mWindow, mGUIManager, mCamera );
} else {
attachCamera( );
}
}
145 void AvatarController::setAvatar( Avatar* avatar )
{
mAvatar = avatar;
createAvatarCameras( avatar->getAvatarSceneNode( ) );
attachCamera( );
}
154 void AvatarController::runCommand( const std::string &command, const std::string &args )
{
if ( RunToggle == command ) {
mIsRunning = true;
} else if ( RunToggle.getInverseCommand( ) == command ) {
mIsRunning = false;
} else if ( ToggleCameraAttached == command )
{
if ( mIsAttached ) {
detachCamera( );
} else {
attachCamera( );
}
} else if ( CharacterMoveForward == command ) {
mMovementDirection.x = 1;
} else if ( CharacterMoveForward.getInverseCommand( ) == command ) {
mMovementDirection.x = 0;
} else if ( CharacterMoveBackward == command ) {
mMovementDirection.x = -1;
} else if ( CharacterMoveBackward.getInverseCommand( ) == command ) {
mMovementDirection.x = 0;
} else if ( CharacterStrafeLeft == command ) {
mMovementDirection.z = -1;
} else if ( CharacterStrafeLeft.getInverseCommand( ) == command ) {
mMovementDirection.z = 0;
} else if ( CharacterStrafeRight == command ) {
mMovementDirection.z = 1;
} else if ( CharacterStrafeRight.getInverseCommand( ) == command ) {
mMovementDirection.z = 0;
} else if ( CharacterMoveUpwards == command ) {
mMovementDirection.y = 1;
} else if ( CharacterMoveUpwards.getInverseCommand( ) == command ) {
mMovementDirection.y = 0;
} else if ( CharacterMoveDownwards == command ) {
mMovementDirection.y = -1;
} else if ( CharacterMoveDownwards.getInverseCommand( ) == command ) {
mMovementDirection.y = 0;
/* } else if ( CharacterRotateLeft == command ) {
mAvatarCamera->yaw( Ogre::Degree( -15 ) );
} else if ( CharacterRotateRight == command ) {
mAvatarCamera->yaw( Ogre::Degree( 15 ) );*/
} else if ( MoveCameraTo == command ) {
if ( !mIsAttached ) {
Ember::Tokeniser tokeniser;
tokeniser.initTokens( args );
std::string x = tokeniser.nextToken( );
std::string y = tokeniser.nextToken( );
std::string z = tokeniser.nextToken( );
if ( x == "" || y == "" || z == "" ) {
return;
} else {
Ogre::Vector3 position( Ogre::StringConverter::parseReal( x ), Ogre::StringConverter::parseReal( y ), Ogre::StringConverter::parseReal( z ) );
mFreeFlyingCameraNode->setPosition( position );
}
}
}
}
214 void AvatarController::detachCamera( )
{
mIsAttached = false;
mAvatarCamera->attach( mFreeFlyingCameraNode );
//mAvatarCamera->setMode( AvatarCamera::MODE_FIRST_PERSON );
}
222 void AvatarController::attachCamera( )
{
mIsAttached = true;
mAvatarCamera->attach( mAvatar->getAvatarSceneNode( ) );
//mAvatarCamera->setMode( AvatarCamera::MODE_FIRST_PERSON );
}
230 bool AvatarController::frameStarted( const Ogre::FrameEvent& event )
{
if ( mDecalObject )
{
///hide the decal when we're close to it
if ( mDecalNode->getWorldPosition( ).distance( mAvatar->getAvatarSceneNode( )->getWorldPosition( ) ) < 1 ) {
mDecalNode->setVisible( false );
}
}
// if ( mDecalObject ) {
// Ogre::Real newSize = mPulsatingController->calculate( event.timeSinceLastFrame );
// //mDecalNode->setScale( Ogre::Vector3( newSize, 1.0f, newSize ) );
// // mDecalNode->yaw( Ogre::Radian( 0.1f ) );
// }
// EmberPagingSceneManager* mScnMgr = static_cast<EmberPagingSceneManager*>( EmberOgre::getSingleton( ).getSceneManager( ) );
// if ( mGUIManager->getInput( )->isKeyDown( SDLK_F4 ) ) {
// /* Real change;
// mScnMgr->getOption( "MaxPixelError", &change );
// change -= 0.5f;
// mScnMgr->setOption( "MaxPixelError", &change ); */
// --Ogre::PagingLandScapeOptions::getSingleton( ).maxPixelError;
// Ogre::PagingLandScapeOptions::getSingleton( ).calculateCFactor( );
// mScnMgr->WorldDimensionChange( );
// }
// if ( mGUIManager->getInput( )->isKeyDown( SDLK_F5 ) ) {
// /* Real change;
// mScnMgr->getOption( "MaxPixelError", &change );
// change += 0.5f;
// mScnMgr->setOption( "MaxPixelError", &change ); */
// ++Ogre::PagingLandScapeOptions::getSingleton( ).maxPixelError;
// Ogre::PagingLandScapeOptions::getSingleton( ).calculateCFactor( );
// mScnMgr->WorldDimensionChange( );
// }
//
movementForFrame = AvatarControllerMovement( );
/* if ( mMovementDirection != Ogre::Vector3::ZERO ) {*/
movementForFrame.mode = mIsRunning ? AvatarMovementMode::MM_RUN : AvatarMovementMode::MM_WALK;
movementForFrame.isMoving = true;
movementForFrame.movementDirection = mMovementDirection;
movementForFrame.timeSlice = event.timeSinceLastFrame;
if ( movementForFrame.mode != mPreviousMovementForFrame.mode ) {
EventMovementModeChanged.emit( movementForFrame.mode );
}
// } else {
// }
// if ( mGUIManager->isInMovementKeysMode( ) ) {
// movementForFrame.movementDirection = Ogre::Vector3::ZERO;
// movementForFrame.mIsRunning = false;
// movementForFrame.isMoving = false;
/* checkMovementKeys( event, EmberOgre::getSingleton( ).getInput( ) );
movementForFrame.timeSlice = event.timeSinceLastFrame;
} */
if ( mIsAttached ) {
// mAvatarCamera->adjustForTerrain( );
mAvatar->updateFrame( movementForFrame );
} else {
Ogre::Real scaler = 50;
//make this inverse, so that when the run key is pressed, the free flying camera goes slower
//this is since we assume that one wants to go fast when in free flying mode
if ( movementForFrame.mode == AvatarMovementMode::MM_RUN ) {
scaler = 10;
}
Ogre::Vector3 correctDirection( movementForFrame.movementDirection.z, movementForFrame.movementDirection.y, -movementForFrame.movementDirection.x );
mFreeFlyingCameraNode->translate( mAvatarCamera->getOrientation( false ) * ( correctDirection * movementForFrame.timeSlice * scaler ) );
}
mPreviousMovementForFrame = movementForFrame;
return true;
}
314 const AvatarControllerMovement & AvatarController::getCurrentMovement( ) const
{
return movementForFrame;
}
320 AvatarCamera* AvatarController::getAvatarCamera( ) const
{
return mAvatarCamera;
}
325 void AvatarController::entityPicker_PickedEntity( const EntityPickResult& result, const MousePickerArgs& args )
{
///don't do this now that we have a "move to" option in the menu, since it will confuse the users
/* if ( args.pickType == MPT_DOUBLECLICK ) {
moveToPoint( result.position );
}*/
}
333 void AvatarController::moveToPoint( const Ogre::Vector3& point )
{
if ( !mDecalNode ) {
createDecal( point );
}
if ( mDecalNode ) {
///make sure it's at the correct height, since the visibility of it is determined by the bounding box
Ogre::Real height = EmberOgre::getSingleton( ).getTerrainGenerator( )->getAdapter( )->getHeightAt( point.x, point.z );
mDecalNode->setPosition( Ogre::Vector3( point.x, height, point.z ) );
mDecalNode->setVisible( true );
}
WFMath::Vector<3> atlasVector = Ogre2Atlas_Vector3( point );
WFMath::Point<3> atlasPos( atlasVector.x( ), atlasVector.y( ), atlasVector.z( ) );
/* WFMath::Point<3> atlas2dPos( atlasVector.x( ), atlasVector.y( ), 0 );
WFMath::Point<3> avatar2dPos( mAvatar->getAvatarEmberEntity( )->getPosition( ).x( ), mAvatar->getAvatarEmberEntity( )->getPosition( ).y( ), 0 );
WFMath::Vector<3> direction( 1, 0, 0 );
direction = direction.rotate( mAvatar->getAvatarEmberEntity( )->getOrientation( ) );
WFMath::Vector<3> directionToPoint = atlas2dPos - avatar2dPos;
WFMath::Quaternion rotation;
rotation = rotation.rotation( directionToPoint, direction );*/
//Ember::EmberServices::getSingletonPtr( )->getServerService( )->moveInDirection( WFMath::Vector<3>( 0, 0, 0 ), rotation );
Ember::EmberServices::getSingletonPtr( )->getServerService( )->moveToPoint( atlasPos );
}
362 void AvatarController::teleportTo( const Ogre::Vector3& point, EmberEntity* locationEntity )
{
WFMath::Vector<3> atlasVector = Ogre2Atlas_Vector3( point );
WFMath::Point<3> atlasPos( atlasVector.x( ), atlasVector.y( ), atlasVector.z( ) );
Ember::EmberServices::getSingletonPtr( )->getServerService( )->place( mAvatar->getAvatarEmberEntity( ), locationEntity, atlasPos );
}
372 void AvatarController::createDecal( Ogre::Vector3 position )
{
try {
// Create object MeshDecal
Ogre::SceneManager* sceneManager = EmberOgre::getSingleton( ).getSceneManager( );
Ogre::NameValuePairList params;
params["materialName"] = "/global/ember/terraindecal";
params["width"] = StringConverter::toString( 2 );
params["height"] = StringConverter::toString( 2 );
params["sceneMgrInstance"] = sceneManager->getName( );
mDecalObject = sceneManager->createMovableObject(
"AvatarControllerMoveToDecal",
"PagingLandScapeMeshDecal",
¶ms );
// Add MeshDecal to Scene
mDecalNode = sceneManager->createSceneNode( "AvatarControllerMoveToDecalNode" );
///the decal code is a little shaky and relies on us setting the position of the node before we add the moveable object
EmberOgre::getSingleton( ).getWorldSceneNode( )->addChild( mDecalNode );
mDecalNode->setPosition( position );
mDecalNode->attachObject( mDecalObject );
// mDecalNode->showBoundingBox( true );
mPulsatingController = new Ogre::WaveformControllerFunction( Ogre::WFT_SINE, 1, 0.33, 0.25 );
} catch ( const Ogre::Exception& ex )
{
S_LOG_WARNING( "Error when creating terrain decal: " << ex.what( ) );
}
}
}
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef AVATARCONTROLLER_H
#define AVATARCONTROLLER_H
#include "EmberOgrePrerequisites.h"
// #include <SDL.h>
#include <sigc++/trackable.h>
#include "input/Input.h"
#include "input/InputCommandMapper.h"
#include "framework/ConsoleObject.h"
#include "EntityWorldPickListener.h"
namespace EmberOgre {
36 class Avatar;
37 class EmberEntity;
38 class AvatarCamera;
40 class GUIManager;
42 class InputManager;
43 class Input;
44 class AvatarController;
/**
The movement mode of the avatar, run or walk.
*/
49 class AvatarMovementMode {
public:
enum Mode
{
MM_WALK = 0,
MM_RUN = 1
};
};
/**
Used for sending the current desired movement to the actual avatar.
*/
struct AvatarControllerMovement
{
AvatarControllerMovement( );
float rotationDegHoriz;
float rotationDegVert;
Ogre::Real timeSlice;
Ogre::Vector3 movementDirection;
AvatarMovementMode::Mode mode;
bool isMoving;
Ogre::Quaternion cameraOrientation;
};
/**
Listens for left mouse button pressed in movement mode and moves the character forward.
*/
78 class AvatarControllerInputListener
{
public:
81 AvatarControllerInputListener( AvatarController& controller );
protected:
85 void input_MouseButtonPressed( Input::MouseButton button, Input::InputMode mode );
86 void input_MouseButtonReleased( Input::MouseButton button, Input::InputMode mode );
87 AvatarController& mController;
};
/**
Controls the avatar. All avatar movement is handled by an instance of this class.
*/
93 class AvatarController
94 : public Ogre::FrameListener,
95 public sigc::trackable,
96 public Ember::ConsoleObject
{
public:
99 friend class AvatarControllerInputListener;
101 AvatarController( Avatar* avatar, Ogre::RenderWindow* window, GUIManager* guiManager, Ogre::Camera* camera );
103 virtual ~AvatarController( );
/**
Each frame we check if we should update the avatar.
*/
108 virtual bool frameStarted( const Ogre::FrameEvent & event );
/**
Emitted when the movement mode changes between run and walk.
*/
114 sigc::signal<void, AvatarMovementMode::Mode> EventMovementModeChanged;
118 void createAvatarCameras( Ogre::SceneNode* avatarSceneNode );
/**
* Gets the AvatarCamera.
* @return
*/
124 AvatarCamera* getAvatarCamera( ) const;
/**
* Detaches the camera from the avatar and attaches it to the free flying node.
*/
129 void detachCamera( );
/**
* Attaches the camera to the avatar.
*/
134 void attachCamera( );
/**
* Gets the current movement for this frame.
* @return
*/
140 const AvatarControllerMovement& getCurrentMovement( ) const;
142 const Ember::ConsoleCommandWrapper RunToggle;
143 const Ember::ConsoleCommandWrapper ToggleCameraAttached;
145 const Ember::ConsoleCommandWrapper CharacterMoveForward;
146 const Ember::ConsoleCommandWrapper CharacterMoveBackward;
147 const Ember::ConsoleCommandWrapper CharacterMoveDownwards;
148 const Ember::ConsoleCommandWrapper CharacterMoveUpwards;
149 const Ember::ConsoleCommandWrapper CharacterStrafeLeft;
150 const Ember::ConsoleCommandWrapper CharacterStrafeRight;
/* const Ember::ConsoleCommandWrapper CharacterRotateLeft;
const Ember::ConsoleCommandWrapper CharacterRotateRight;*/
154 const Ember::ConsoleCommandWrapper MoveCameraTo;
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
162 virtual void runCommand( const std::string &command, const std::string &args );
/**
Moves the avatar to the specified point.
A terrain decal will be shown.
*/
168 void moveToPoint( const Ogre::Vector3& point );
/**
* Teleports the avatar to the specified point.
* @param point
* @param locationEntity
*/
175 void teleportTo( const Ogre::Vector3& point, EmberEntity* locationEntity );
protected:
179 InputCommandMapper mMovementCommandMapper;
181 Ogre::RenderWindow* mWindow;
183 GUIManager* mGUIManager;
// void checkMovementKeys( const Ogre::FrameEvent & event, const Input& input );
189 AvatarCamera* mAvatarCamera;
190 void setAvatar( Avatar* avatar );
191 Ogre::Camera* mCamera;
/**
* Avatar
*/
197 Avatar* mAvatar;
199 EmberEntity* mEntityUnderCursor;
200 EmberEntity* mSelectedEntity;
AvatarControllerMovement movementForFrame, mPreviousMovementForFrame;
204 Ogre::SceneNode* mFreeFlyingCameraNode;
205 bool mIsAttached;
/**
True if we're in running mode.
*/
209 bool mIsRunning;
211 Ogre::Vector3 mMovementDirection;
/**
Listen for double clicks and send the avatar to the double clicked position.
*/
216 void entityPicker_PickedEntity( const EntityPickResult& result, const MousePickerArgs& args );
/**
Creates the terrain decal needed for displaying where the avatar is heading.
*/
221 void createDecal( Ogre::Vector3 position );
223 Ogre::MovableObject* mDecalObject;
224 Ogre::SceneNode* mDecalNode;
225 Ogre::WaveformControllerFunction* mPulsatingController;
227 AvatarControllerInputListener mControllerInputListener;
};
}
#endif // AvatarController_H
/*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "EmberEntity.h"
#include "EmberPhysicalEntity.h"
// #include "PersonEmberEntity.h"
#include "framework/ConsoleBackend.h"
#include "Avatar.h"
#include "GUIManager.h"
#include "model/Model.h"
#include "AvatarEmberEntity.h"
#include "EmberOgre.h"
#include "MousePicker.h"
#include <Eris/Entity.h>
#include <Eris/Avatar.h>
#include <OgreTagPoint.h>
namespace EmberOgre {
38 AvatarEmberEntity::AvatarEmberEntity( const std::string& id, Eris::TypeInfo* type, Eris::View* vw, Ogre::SceneManager* sceneManager, Eris::Avatar* erisAvatar ) : EmberPhysicalEntity( id, type, vw, sceneManager ), SetAttachedOrientation( "setattachedorientation", this, "Sets the orienation of an item attached to the avatar: <attachpointname> <x> <y> <z> <degrees>" ),
39 mAvatar( 0 ), mErisAvatar( erisAvatar )
{
}
43 AvatarEmberEntity::~AvatarEmberEntity( )
{}
47 void AvatarEmberEntity::runCommand( const std::string &command, const std::string &args )
{
if( SetAttachedOrientation == command ) {
Ember::Tokeniser tokeniser;
tokeniser.initTokens( args );
std::string attachPointName = tokeniser.nextToken( );
if ( attachPointName != "" ) {
std::string x = tokeniser.nextToken( );
std::string y = tokeniser.nextToken( );
std::string z = tokeniser.nextToken( );
std::string degrees = tokeniser.nextToken( );
if ( x != "" && y != "" && z != "" && degrees != "" ) {
Ogre::Degree ogreDegrees( Ogre::StringConverter::parseReal( degrees ) );
Ogre::Quaternion rotation( ogreDegrees, Ogre::Vector3( Ogre::StringConverter::parseReal( x ), Ogre::StringConverter::parseReal( y ), Ogre::StringConverter::parseReal( z ) ) );
if ( getModel( ) ) {
const Model::Model::AttachPointWrapperStore* attachPoints = getModel( )->getAttachedPoints( );
if ( attachPoints ) {
for ( Model::Model::AttachPointWrapperStore::const_iterator I = attachPoints->begin( ); I != attachPoints->end( ); ++I ) {
if ( I->AttachPointName == attachPointName ) {
I->TagPoint->setOrientation( rotation );
}
}
}
}
}
}
}
}
76 void AvatarEmberEntity::init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp )
{
EmberPhysicalEntity::init( ge, fromCreateOp );
mModel->setQueryFlags( MousePicker::CM_AVATAR );
}
84 void AvatarEmberEntity::onMoved( )
{
//EmberPhysicalEntity::onMoved( );
if ( getAvatar( ) ) {
getAvatar( )->movedInWorld( );
}
Eris::Entity::onMoved( );
}
94 void AvatarEmberEntity::onImaginary( const Atlas::Objects::Root& act )
{
Atlas::Message::Element attr;
if ( act->copyAttr( "description", attr ) != 0 || !attr.isString( ) ) {
return;
}
/// Make the message appear in the chat box
GUIManager::getSingleton( ).AppendAvatarImaginary.emit( getName( ) + " " + attr.String( ) );
}
/*
void AvatarEmberEntity::handleTalk( const std::string &msg )
{
std::string message = "<";
message.append( getName( ) );
message.append( "> " );
message.append( msg );
GUIManager::getSingleton( ).AppendIGChatLine.emit( message );
std::cout << "TRACE - AVATAR SAYS: [" << message << "]\n" << std::endl;
Ember::ConsoleBackend::getMainConsole( )->pushMessage( message );
}
*/
/*
void AvatarEmberEntity::setVisible( bool vis )
{
//TODO
//mOgreEntity->setVisible( true );
}
*/
//void AvatarEmberEntity::addMember( Entity *e )
126 void AvatarEmberEntity::onChildAdded( Entity *e )
{
//mAvatar->EventAddedEntityToInventory.emit( static_cast<EmberEntity*>( e ) );
EmberOgre::getSingleton( ).getAvatar( )->mEntitiesToBeAddedToInventory.insert( e );
//PersonEmberEntity::addMember( e );
EmberPhysicalEntity::onChildAdded( e );
}
/*void AvatarEmberEntity::rmvMember( Entity *e )*/
137 void AvatarEmberEntity::onChildRemoved( Entity *e )
{
EmberOgre::getSingleton( ).getAvatar( )->EventRemovedEntityFromInventory.emit( static_cast<EmberEntity*>( e ) );
EmberPhysicalEntity::onChildRemoved( e );
// mAvatar->mEntitiesToBeRemovedFromInventory.insert( e );
// PersonEmberEntity::rmvMember( e );
}
// void AvatarEmberEntity::onLocationChanged( Eris::Entity *oldLocation, Eris::Entity *newLocation )
// {
// return EmberEntity::onLocationChanged( oldLocation, newLocation );
//
//
//
// Ogre::Vector3 oldWorldPosition = getSceneNode( )->getWorldPosition( );
// EmberEntity* EmberEntity = dynamic_cast<EmberEntity*>( newLocation );
// Ogre::SceneNode* newOgreParentNode = EmberEntity->getSceneNode( );
//
// /* if ( EmberEntity )
// {
// newOgreParentNode = EmberEntity->getSceneNode( );
// } else {
// newOgreParentNode = EmberOgre::getSingleton( ).getSceneManager( )->getSceneNode( newLocation->getId( ) );
// }*/
//
// if ( getSceneNode( )->getParent( ) ) {
// //detach from our current object and add to the new entity
// getSceneNode( )->getParent( )->removeChild( getSceneNode( )->getName( ) );
// }
// newOgreParentNode->addChild( getSceneNode( ) );
//
//
// // Entity::setContainer( pr );
// Eris::Entity::onLocationChanged( oldLocation, newLocation );
//
// //we adjust the entity so it retains it's former position in the world
// Ogre::Vector3 newWorldPosition = getSceneNode( )->getWorldPosition( );
// getSceneNode( )->translate( oldWorldPosition - newWorldPosition );
// }
179 Ogre::SceneNode* AvatarEmberEntity::getAvatarSceneNode( )
{
return getScaleNode( );
}
}
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef AVATARDIMEENTITY_H
#define AVATARDIMEENTITY_H
namespace Eris
{
25 class Entity;
26 class Avatar;
}
namespace EmberOgre {
namespace Model {
32 class Model;
}
class EmberPhysicalEntity;
36 class EmberEntity;
37 class Avatar;
/**
* This is the main player avatar. We want this one to behave a little different
* than the other game entities, thus it has it's own subclass.
*
*/
44 class AvatarEmberEntity
45 : public EmberPhysicalEntity,
46 public Ember::ConsoleObject
{
public:
50 AvatarEmberEntity( const std::string& id, Eris::TypeInfo* type, Eris::View* vw, Ogre::SceneManager* sceneManager, Eris::Avatar* erisAvatar );
51 virtual ~AvatarEmberEntity( );
/**
* used by the main application to set the EmberOgre::Avatar connected to this instance
*/
56 inline void setAvatar( Avatar* avatar );
57 inline Avatar* getAvatar( );
/**
* returns the Ogre::SceneNode which represents the avatar
*/
62 Ogre::SceneNode* getAvatarSceneNode( );
/**
* Returns the Eris Avatar instance.
* @return
*/
68 inline Eris::Avatar* getErisAvatar( );
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
75 virtual void runCommand( const std::string &command, const std::string &args );
77 const Ember::ConsoleCommandWrapper SetAttachedOrientation;
protected:
81 virtual void onChildAdded( Entity *e );
82 virtual void onChildRemoved( Entity *e );
/**Eris methods, see Eris::Entity.h for documentation */
// virtual void handleTalk( const std::string &msg );
86 virtual void onMoved( );
87 virtual void onImaginary( const Atlas::Objects::Root& act );
/* virtual void addMember( Entity *e );
virtual void rmvMember( Entity *e );*/
//virtual void setVisible( bool vis );
//virtual void setContainer( Eris::Entity *pr );
//virtual void onLocationChanged( Eris::Entity *oldLocation, Eris::Entity *newLocation );
93 virtual void init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp );
96 Avatar* mAvatar;
97 Eris::Avatar* mErisAvatar;
};
///inline implementations
101 void AvatarEmberEntity::setAvatar( Avatar* avatar )
{
mAvatar = avatar;
}
105 Avatar* AvatarEmberEntity::getAvatar( )
{
return mAvatar;
}
109 Eris::Avatar* AvatarEmberEntity::getErisAvatar( )
{
return mErisAvatar;
}
}
#endif // AVATARDIMEENTITY_H
1 //
// C++ Implementation: CameraMount
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2006
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "CameraMount.h"
namespace EmberOgre {
27 CameraMount::CameraMount( )
{
}
32 CameraMount::~CameraMount( )
{
}
}
1 //
// C++ Interface: CameraMount
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2006
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGRECAMERAMOUNT_H
#define EMBEROGRECAMERAMOUNT_H
namespace EmberOgre {
/**
@author Erik Hjortsberg
*/
31 class CameraMount{
public:
33 CameraMount( );
35 ~CameraMount( );
};
}
#endif
/*
ConsoleObjectImpl.cpp by Miguel Guzman ( Aglanor )
Copyright ( C ) 2002 Miguel Guzman & The Worldforge Project
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// config headers
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// system headers
// library headers
#include "EmberOgrePrerequisites.h"
// local headers
#include "ConsoleObjectImpl.h"
#include "framework/ConsoleBackend.h"
#include "framework/Tokeniser.h"
#include "main/Application.h"
// #include <SDL.h>
template<> EmberOgre::ConsoleObjectImpl* Ember::Singleton<EmberOgre::ConsoleObjectImpl>::ms_Singleton = 0;
namespace EmberOgre {
43 ConsoleObjectImpl::ConsoleObjectImpl( void ) :
Quit( "quit", this, "Quit Ember." ),
45 ToggleErisPolling( "toggle_erispolling", this, "Switch server polling on and off." )
{
}
48 ConsoleObjectImpl::~ConsoleObjectImpl( )
{
}
54 void ConsoleObjectImpl::runCommand( const std::string &command, const std::string &args )
{
if( command == Quit.getCommand( ) ) {
Ember::ConsoleBackend::getMainConsole( )->pushMessage( "Bye" );
quit( );
} else if ( ToggleErisPolling == command ){
Ember::Application::getSingleton( ).setErisPolling( !Ember::Application::getSingleton( ).getErisPolling( ) );
}
}
64 void ConsoleObjectImpl::quit( )
{
Ember::Application::getSingleton( ).quit( );
}
}
1 /*
ConsoleObjectImpl.h by Miguel Guzman ( Aglanor )
Copyright ( C ) 2002 Miguel Guzman & The Worldforge Project
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __EmberOgre_ConsoleObjectImpl_H__
#define __EmberOgre_ConsoleObjectImpl_H__
#include "framework/ConsoleObject.h"
#include "framework/Singleton.h"
namespace EmberOgre {
27 class ConsoleObjectImpl: public Ember::ConsoleObject, public Ember::Singleton<ConsoleObjectImpl>
{
public:
31 ConsoleObjectImpl( void );
32 ~ConsoleObjectImpl( );
/**
* Receive commands from console
*/
37 void runCommand( const std::string &command, const std::string &args );
private:
43 void quit( );
/// List of Ogre's console commands
46 const Ember::ConsoleCommandWrapper Quit;
47 const Ember::ConsoleCommandWrapper ToggleErisPolling;
}; // End of class declaration
}
#endif
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "EmberEntity.h"
#include "framework/Service.h"
#include "framework/ConsoleBackend.h"
#include "services/EmberServices.h"
#include "services/sound/SoundService.h"
#include "EmberEntityFactory.h"
#include "MotionManager.h"
#include "GUIManager.h"
#include "terrain/TerrainArea.h"
#include "MathConverter.h"
#include "EmberOgre.h"
#include <OgreWireBoundingBox.h>
#include <OgreException.h>
#include <Mercator/Area.h>
//#include <Atlas/Objects/ObjectsFwd.h>
#include <Eris/TypeInfo.h>
#include <Eris/View.h>
#include <Atlas/Formatter.h>
#include <Atlas/Objects/Decoder.h>
#include <Atlas/Codecs/XML.h>
#include <Atlas/Message/MEncoder.h>
#include <Atlas/Message/QueuedDecoder.h>
#include "model/Model.h"
using namespace Ogre;
namespace Ogre {
/**
This is just like a WireBoundBox but not aligned to the axes, hence it will correctly line up according to it's orientation.
*/
56 class OOBBWireBoundingBox : public WireBoundingBox
{
public:
60 void getWorldTransforms( Matrix4* xform ) const
{
SimpleRenderable::getWorldTransforms( xform );
}
//-----------------------------------------------------------------------
65 const Quaternion& getWorldOrientation( void ) const
{
return SimpleRenderable::getWorldOrientation( );
}
//-----------------------------------------------------------------------
70 const Vector3& getWorldPosition( void ) const
{
return SimpleRenderable::getWorldPosition( );
}
};
};
namespace EmberOgre {
95 const std::string EmberEntity::MODE_STANDING( "standing" );
96 const std::string EmberEntity::MODE_RUNNING( "running" );
97 const std::string EmberEntity::MODE_WALKING( "walking" );
98 const std::string EmberEntity::MODE_SWIMMING( "swimming" );
99 const std::string EmberEntity::MODE_FLOATING( "floating" );
100 const std::string EmberEntity::MODE_FIXED( "fixed" );
102 const std::string EmberEntity::BboxMaterialName( "BaseYellowNoLightning" );
105 EmberEntity::EmberEntity( const std::string& id, Eris::TypeInfo* ty, Eris::View* vw, Ogre::SceneManager* sceneManager )
:
Eris::Entity( id, ty, vw )
, mIsInitialized( false )
, mIsInMotionManager( false )
, mErisEntityBoundingBox( 0 )
, mOgreNode( 0 )
, mTerrainArea( 0 )
{
createSceneNode( sceneManager );
}
117 EmberEntity::~EmberEntity( )
{
//detach all children so we don't destroy them
while ( getSceneNode( )->numChildren( ) ) {
getSceneNode( )->removeChild( ( short unsigned int )0 );
}
Ogre::SceneNode* parent = static_cast<Ogre::SceneNode*>( getSceneNode( )->getParent( ) );
if ( parent ) {
parent->removeAndDestroyChild( getSceneNode( )->getName( ) );
} else {
getSceneNode( )->getCreator( )->destroySceneNode( getSceneNode( )->getName( ) );
}
///make sure it's not in the MotionManager
///TODO: keep a marker in the entity so we don't need to call this for all entities
MotionManager::getSingleton( ).removeEntity( this );
if ( mErisEntityBoundingBox ) {
mErisEntityBoundingBox->getParentSceneNode( )->getCreator( )->destroySceneNode( mErisEntityBoundingBox->getParentSceneNode( )->getName( ) );
}
delete mErisEntityBoundingBox;
//mSceneManager->destroySceneNode( getSceneNode( )->getName( ) );
}
141 void EmberEntity::init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp )
{
Eris::Entity::init( ge, fromCreateOp );
synchronizeWithServer( );
// set the Ogre node position and orientation based on Atlas data
std::stringstream ss;
ss << "Entity " << getId( ) << "( " << getName( ) << " ) placed at ( " << getPredictedPos( ).x( ) << ", " << getPredictedPos( ).y( ) << ", " << getPredictedPos( ).x( ) << " )";
S_LOG_VERBOSE( ss.str( ) );
if ( hasAttr( "area" ) ) {
mTerrainArea = std::auto_ptr<Terrain::TerrainArea>( new Terrain::TerrainArea( this ) );
if ( mTerrainArea->init( ) ) {
addArea( mTerrainArea.get( ) );
}
}
mIsInitialized = true;
}
163 void EmberEntity::synchronizeWithServer( )
{
if ( getPosition( ).isValid( ) ) {
getSceneNode( )->setPosition( Atlas2Ogre( getPredictedPos( ) ) );
adjustPosition( );
}
if ( getOrientation( ).isValid( ) ) {
getSceneNode( )->setOrientation( Atlas2Ogre( getOrientation( ) ) );
}
}
176 void EmberEntity::createSceneNode( Ogre::SceneManager* sceneManager )
{
EmberEntity* container = getEmberLocation( );
if ( container == 0 ) {
//S_LOG_VERBOSE( "Entity created in limbo: "<< this->getId( ) << " ( " << this->getName( ) << " )" )
mOgreNode = sceneManager->createSceneNode( getId( ) );
} else {
Ogre::SceneNode * node = container->getSceneNode( );
mOgreNode = node->createChildSceneNode( getId( ) );
}
}
190 void EmberEntity::updateMotion( Ogre::Real timeSlice )
{
getSceneNode( )->setPosition( Atlas2Ogre( getPredictedPos( ) ) );
adjustPosition( );
//if there's a debug bounding box for the eris entity, update it's position
if ( mErisEntityBoundingBox ) {
mErisEntityBoundingBox->getParentSceneNode( )->setPosition( getSceneNode( )->getPosition( ) );
mErisEntityBoundingBox->getParentSceneNode( )->setOrientation( getSceneNode( )->getOrientation( ) );
}
}
206 void EmberEntity::onMoved( )
{
Eris::Entity::onMoved( );
const WFMath::Quaternion& orient = getOrientation( );
getSceneNode( )->setOrientation( Atlas2Ogre( orient ) );
updateMotion( 0 );
}
214 void EmberEntity::setMoving( bool moving )
{
// Call the overridden method
Eris::Entity::setMoving( moving );
MotionManager* motionManager = &MotionManager::getSingleton( );
if ( moving ) {
//the entity is moving
if ( !mIsInMotionManager ) {
motionManager->addEntity( this );
mIsInMotionManager = true;
}
} else {
//the entity has stopped moving
if ( mIsInMotionManager ) {
motionManager->removeEntity( this );
mIsInMotionManager = false;
}
}
}
238 void EmberEntity::onTalk( const Atlas::Objects::Operation::RootOperation& talkArgs )
{
const std::vector<Atlas::Objects::Root>& args = talkArgs->getArgs( );
if ( args.empty( ) ) {
Eris::Entity::onTalk( talkArgs );
return;
}
const Atlas::Objects::Root& talk = args.front( );
if ( !talk->hasAttr( "say" ) ) {
Eris::Entity::onTalk( talkArgs );
return;
}
///some talk operations come with a predefined set of suitable responses, so we'll store those so that they can later on be queried by the GUI for example
mSuggestedResponses.clear( );
if ( talk->hasAttr( "responses" ) ) {
if ( talk->getAttr( "responses" ).isList( ) ) {
const Atlas::Message::ListType & responseList = talk->getAttr( "responses" ).asList( );
Atlas::Message::ListType::const_iterator I = responseList.begin( );
for( ; I != responseList.end( ); ++I ) {
mSuggestedResponses.push_back( I->asString( ) );
}
}
}
const std::string& msg = talk->getAttr( "say" ).asString( );
std::string message = "<";
message.append( getName( ) );
message.append( ", " );
const std::string& type = getType( )->getName( ); // Eris type as a string
message.append( type );
message.append( "> " );
message.append( msg );
S_LOG_VERBOSE( "Entity says: [" << message << "]\n" )
/// Make the message appear in the chat box
GUIManager::getSingleton( ).AppendIGChatLine.emit( msg, this );
/// Make a sound in OpenAL
// Ember::EmberServices::getSingleton( ).getSoundService( )->playTalk( msg,
// getPosition( ), getOrientation( ) );
/// Call the method of the base class ( since we've overloaded it )
Eris::Entity::onTalk( talkArgs );
}
294 void EmberEntity::onSoundAction( const Atlas::Objects::Operation::RootOperation & op )
{
Eris::Entity::onSoundAction( op );
}
300 void EmberEntity::onVisibilityChanged( bool vis )
{
checkVisibility( vis );
Eris::Entity::onVisibilityChanged( vis );
}
306 void EmberEntity::checkVisibility( bool vis )
{
///since we don't want to show all entities solely by their server flags ( for example, an inventory item belonging to a character might not be shown even though the server thinks it's visible ) we have to some more checks before we decide whether to show this or not
EmberEntity* container = static_cast<EmberEntity*>( getLocation( ) );
if ( container ) {
///check with the parent first if we should show ourselves
if ( vis && container->allowVisibilityOfMember( this ) ) {
///don't cascade, only change the top node
setVisible( true );
} else {
setVisible( false );
}
} else {
setVisible( vis );
}
}
325 void EmberEntity::setVisible( bool visible )
{
///when entities are hidden, we detach them from the rendering scene graph altogether. this speeds up Ogre since it doesn't have to calculate visibility for nodes that are hidden anyway
if ( !visible ) {
if ( getSceneNode( )->getParent( ) ) {
getSceneNode( )->getParent( )->removeChild( getSceneNode( ) );
}
} else {
if ( getLocation( ) ) {
if ( !getSceneNode( )->getParent( ) ) {
getEmberLocation( )->getSceneNode( )->addChild( getSceneNode( ) );
}
}
}
getSceneNode( )->setVisible( visible && getLocation( ), false );
}
344 void EmberEntity::adjustPosition( )
{
if ( getPredictedPos( ).isValid( ) ) {
adjustPosition( Atlas2Ogre( getPredictedPos( ) ) );
}
}
351 void EmberEntity::adjustPosition( const Ogre::Vector3& position )
{
if ( mMovementMode == MM_FIXED ) {
} else {
EmberEntity* container = getEmberLocation( );
if ( container ) {
container->adjustPositionForContainedNode( this, position );
}
}
}
363 const Ogre::Vector3& EmberEntity::getOffsetForContainedNode( const Ogre::Vector3& localPosition, EmberEntity* const entity )
{
///send it upwards until we get a an entity which knows how to set the position ( we'll in most cases end up in the world which will adjust the height a bit )
EmberEntity* container = getEmberLocation( );
if ( container ) {
//TerrainPosition derivedPosition( getPredictedPos( ).x( ) + position.x( ), getPredictedPos( ).y( ) + position.y( ) );
return container->getOffsetForContainedNode( localPosition + getSceneNode( )->getPosition( ), entity );
} else {
return Ogre::Vector3::ZERO;
}
}
379 void EmberEntity::adjustPositionForContainedNode( EmberEntity* const entity, const Ogre::Vector3& position )
{
Ogre::SceneNode* sceneNode = entity->getSceneNode( );
//Ogre::Vector3 position = sceneNode->getPosition( );
const Ogre::Vector3& offset = getOffsetForContainedNode( position, entity );
if ( offset != Ogre::Vector3::ZERO ) {
sceneNode->setPosition( position + offset );
}
}
391 void EmberEntity::onLocationChanged( Eris::Entity *oldLocation )
{
if ( getLocation( ) == oldLocation )
{
S_LOG_WARNING( "Same new location as old for entity: " << this->getId( ) << " ( " << this->getName( ) << " )" );
return Eris::Entity::onLocationChanged( oldLocation );
}
Eris::Entity::onLocationChanged( oldLocation );
///if we're attached to something, detach from it
detachFromModel( );
if ( !getLocation( ) ) {
return;
} else {
EmberEntity* newLocationEntity = getEmberLocation( );
const Ogre::Vector3 oldWorldPosition = getSceneNode( )->getWorldPosition( );
// const Ogre::Quaternion oldWorldOrientation = getSceneNode( )->getWorldOrientation( );
if ( getSceneNode( )->getParentSceneNode( ) ) {
///detach from our current object
getSceneNode( )->getParentSceneNode( )->removeChild( getSceneNode( )->getName( ) );
}
if ( newLocationEntity ) {
// add to the new entity
newLocationEntity->getSceneNode( )->addChild( getSceneNode( ) );
S_LOG_VERBOSE( "Entity: " << this->getId( ) << " ( " << this->getName( ) << " ) relocated to: "<< newLocationEntity->getId( ) << " ( " << newLocationEntity->getName( ) << " )" );
if ( getPosition( ).isValid( ) ) {
///note that in some instances, for instance when the avatar enters the sty, the position isn't updated yet, which will make the avatar "snap" to an incorrect position ( since the parent node has changed ) until next frame, when the position should have been updated
getSceneNode( )->setPosition( Atlas2Ogre( getPredictedPos( ) ) );
adjustPosition( );
std::stringstream ss;
ss << getPredictedPos( );
S_LOG_VERBOSE( "New position for entity: " << this->getId( ) << " ( " << this->getName( ) << " ) :" << ss.str( ) );
}
if ( getOrientation( ).isValid( ) ) {
getSceneNode( )->setOrientation( Atlas2Ogre( getOrientation( ) ) );
std::stringstream ss;
ss << getOrientation( );
S_LOG_VERBOSE( "New orientation for entity: " << this->getId( ) << " ( " << this->getName( ) << " ) :" << ss.str( ) );
}
// getSceneNode( )->rotate( newLocationEntity->getSceneNode( )->getWorldOrientation( ) - oldWorldOrientation );
} else {
///the entity has no current parent, and should be placed in limbo ( hopefully a more correct parent will be submitted in a future LocationChanged event
S_LOG_VERBOSE( "Entity relocated to limbo: "<< this->getId( ) << " ( " << this->getName( ) << " )" );
// mSceneManager->getRootSceneNode( )->addChild( getSceneNode( ) );
}
checkVisibility( isVisible( ) );
///we'll adjust the entity so it retains it's former position in the world, but only for moving entities
///since else we'll get a "gap" when we're waiting on updated positions from the server
///this isn't optimal
if ( isMoving( ) ) {
const Ogre::Vector3& newWorldPosition = getSceneNode( )->getWorldPosition( );
getSceneNode( )->translate( oldWorldPosition - newWorldPosition );
}
}
}
456 void EmberEntity::onAction( const Atlas::Objects::Operation::RootOperation& act )
{
const std::list<std::string> &p = act->getParents( );
std::list<std::string>::const_iterator I = p.begin( );
if ( I == p.end( ) ) return;
const std::string& name = *I;
std::string message = getName( ) + " performs a " + name + ".";
Ember::ConsoleBackend::getMainConsole( )->pushMessage( message );
S_LOG_VERBOSE( "Entity: " << this->getId( ) << " ( " << this->getName( ) << " ) action: " << name );
Entity::onAction( act );
}
472 void EmberEntity::onImaginary( const Atlas::Objects::Root& act )
{
Atlas::Message::Element attr;
if ( act->copyAttr( "description", attr ) && attr.isString( ) ) {
std::string message = getName( ) + " " + attr.asString( ) + ".";
Ember::ConsoleBackend::getMainConsole( )->pushMessage( message );
S_LOG_VERBOSE( "Entity: " << this->getId( ) << " ( " << this->getName( ) << " ) imaginary: " << attr.String( ) );
}
Entity::onImaginary( act );
}
488 bool EmberEntity::allowVisibilityOfMember( EmberEntity* entity ) {
return true;
}
492 const std::vector< std::string >& EmberEntity::getSuggestedResponses( ) const
{
return mSuggestedResponses;
}
497 bool EmberEntity::hasSuggestedResponses( ) const
{
return mSuggestedResponses.size( ) > 0;
}
503 void EmberEntity::addArea( Terrain::TerrainArea* area )
{
///just pass it on to the parent until we get to someone who knows how to handle this ( preferrably the terrain )
if ( getEmberLocation( ) ) {
getEmberLocation( )->addArea( area );
}
}
511 void EmberEntity::onAttrChanged( const std::string& str, const Atlas::Message::Element& v )
{
if ( str == "mode" ) {
parseModeChange( v );
} else if ( str == "bbox" ) {
Entity::onAttrChanged( str, v );
onBboxChanged( );
return;
}
Entity::onAttrChanged( str, v );
}
523 void EmberEntity::parseModeChange( const Atlas::Message::Element& v )
{
const std::string& mode = v.asString( );
MovementMode newMode;
if ( mode.empty( ) ) {
newMode = MM_DEFAULT;
} else if ( mode == MODE_STANDING ) {
newMode = MM_STANDING;
} else if ( mode == MODE_RUNNING ) {
newMode = MM_RUNNING;
} else if ( mode == MODE_WALKING ) {
newMode = MM_WALKING;
} else if ( mode == MODE_SWIMMING ) {
newMode = MM_SWIMMING;
} else if ( mode == MODE_FLOATING ) {
newMode = MM_FLOATING;
} else if ( mode == MODE_FIXED ) {
newMode = MM_FIXED;
} else {
newMode = MM_DEFAULT;
}
onModeChanged( newMode );
}
548 void EmberEntity::onModeChanged( MovementMode newMode )
{
if ( newMode == MM_FIXED ) {
adjustPosition( );
}
mMovementMode = newMode;
}
556 void EmberEntity::setVisualize( const std::string& visualization, bool visualize )
{
if ( visualization == "OgreBBox" ) {
showOgreBoundingBox( visualize );
} else if ( visualization == "ErisBBox" ) {
showErisBoundingBox( visualize );
}
}
565 bool EmberEntity::getVisualize( const std::string& visualization ) const
{
if ( visualization == "OgreBBox" ) {
return getShowOgreBoundingBox( );
} else if ( visualization == "ErisBBox" ) {
return getShowErisBoundingBox( );
}
return false;
}
576 void EmberEntity::showOgreBoundingBox( bool show )
{
getSceneNode( )->showBoundingBox( show );
}
581 void EmberEntity::showErisBoundingBox( bool show )
{
createErisBboxMaterial( );
///if there's no bounding box, create one now
///allowing for some lazy loading
if ( !mErisEntityBoundingBox ) {
mErisEntityBoundingBox = new Ogre::OOBBWireBoundingBox( );
mErisEntityBoundingBox->setMaterial( BboxMaterialName );
Ogre::SceneNode* boundingBoxNode = EmberOgre::getSingleton( ).getWorldSceneNode( )->createChildSceneNode( );
boundingBoxNode->attachObject( mErisEntityBoundingBox );
Ogre::AxisAlignedBox aabb( Atlas2Ogre( getBBox( ) ) );
mErisEntityBoundingBox->setupBoundingBox( aabb );
boundingBoxNode->setPosition( Atlas2Ogre( getPredictedPos( ) ) );
boundingBoxNode->setOrientation( Atlas2Ogre( getOrientation( ) ) );
}
mErisEntityBoundingBox->setVisible( show );
}
605 void EmberEntity::createErisBboxMaterial( )
{
if ( !Ogre::MaterialManager::getSingleton( ).resourceExists( BboxMaterialName ) ) {
Ogre::MaterialPtr baseYellowNoLighting = Ogre::MaterialManager::getSingleton( ).create( BboxMaterialName,
Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME );
baseYellowNoLighting->setLightingEnabled( false );
baseYellowNoLighting->setAmbient( Ogre::ColourValue( 1, 1, 0.7 ) );
baseYellowNoLighting->setDiffuse( Ogre::ColourValue( 1, 1, 0.7 ) );
}
}
616 void EmberEntity::onBboxChanged( )
{
if ( mErisEntityBoundingBox ) {
mErisEntityBoundingBox->setupBoundingBox( Atlas2Ogre( getBBox( ) ) );
}
}
624 bool EmberEntity::getShowOgreBoundingBox( ) const
{
return getSceneNode( )->getShowBoundingBox( );
}
628 bool EmberEntity::getShowErisBoundingBox( ) const
{
return ( mErisEntityBoundingBox && mErisEntityBoundingBox->isVisible( ) );
}
//inline
635 Ogre::SceneNode* EmberEntity::getSceneNode( ) const
{
return mOgreNode;
}
640 EmberEntity* EmberEntity::getEmberLocation( ) const
{
return static_cast<EmberEntity*>( getLocation( ) );
}
646 const Ogre::AxisAlignedBox& EmberEntity::getWorldBoundingBox( bool derive ) const
{
static Ogre::AxisAlignedBox boundingBox( 0, 0, 0, 0, 0, 0 );
return boundingBox;
}
652 const Ogre::Sphere & EmberEntity::getWorldBoundingSphere ( bool derive ) const
{
static Ogre::Sphere sphere;
return sphere;
}
658 std::vector<std::string> EmberEntity::getDefaultUseOperators( )
{
///get the use operations from Eris and return them a simple vector of strings
std::vector<std::string> operators;
Eris::TypeInfoArray types = getUseOperations( );
for ( Eris::TypeInfoArray::iterator I = types.begin( ); I != types.end( ); ++I ) {
operators.push_back( ( *I )->getName( ) );
}
return operators;
}
672 Ogre::SceneManager* EmberEntity::getSceneManager( )
{
assert( mOgreNode );
return mOgreNode->getCreator( );
}
678 static void dumpElement( const std::string &prefix, const std::string &name, const Atlas::Message::Element &e, std::ostream& outstream, std::ostream& logOutstream )
{
if ( e.isMap( ) ) {
logOutstream << prefix << name << ": Dumping Map" << std::endl;
Atlas::Message::MapType::const_iterator itr = e.asMap( ).begin( );
Atlas::Message::MapType::const_iterator end = e.asMap( ).end( );
outstream << prefix << name << ":" << std::endl;
for ( ; itr != end; ++itr ) {
dumpElement( prefix + " ", itr->first, itr->second, outstream, logOutstream );
}
logOutstream << prefix << "Finished Dumping Map" << std::endl;
} else if ( e.isList( ) ) {
logOutstream << prefix << name << ": Dumping List" << std::endl;
Atlas::Message::ListType::const_iterator itr = e.asList( ).begin( );
Atlas::Message::ListType::const_iterator end = e.asList( ).end( );
outstream << prefix << name << ":" << std::endl;
for ( ; itr != end; ++itr ) {
dumpElement( prefix + " ", "", *itr, outstream, logOutstream );
}
logOutstream << prefix << "Finished Dumping List" << std::endl;
} else {
if ( e.isString( ) ) outstream << prefix << name << ": " << e.asString( ) << std::endl;
if ( e.isNum( ) ) outstream << prefix << name << ": " << e.asNum( ) << std::endl;
}
}
705 void EmberEntity::dumpAttributes( std::iostream& outstream, std::ostream& logOutstream ) const
{
logOutstream << "Dumping attributes for entity " << getId( ) << "( " << getName( ) << " )" << std::endl;
Atlas::Message::QueuedDecoder decoder;
//std::fstream file;
Atlas::Codecs::XML codec( outstream, decoder );
Atlas::Formatter formatter( outstream, codec );
Atlas::Message::Encoder encoder( formatter );
formatter.streamBegin( );
encoder.streamMessageElement( getAttributes( ) );
formatter.streamEnd( );
// const Eris::Entity::AttrMap &attribs = getAttributes( );
// Eris::Entity::AttrMap::const_iterator itr = attribs.begin( );
// Eris::Entity::AttrMap::const_iterator end = attribs.end( );
// for ( ; itr != end; ++itr ) {
// dumpElement( "", itr->first, itr->second, outstream, logOutstream );
// }
}
}
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DIMEENTITY_H
#define DIMEENTITY_H
#include "EmberOgrePrerequisites.h"
#include <Atlas/Objects/Entity.h>
#include <Atlas/Objects/Operation.h>
#include <Eris/Entity.h>
namespace Ogre
{
32 class OOBBWireBoundingBox;
}
namespace Mercator
{
37 class Area;
}
40 namespace Eris
{
class View;
}
namespace EmberOgre {
namespace Model {
48 class Model;
}
51 namespace Terrain
{
class TerrainArea;
}
56 class EmberEntityFactory;
/**
* A representation of an Eris::Entity, ie. a world entity.
* Note that most entities in the game world will be of type EmberPhysicalEntity
* as they will have some sort of physical representation.
* For things such as boundaries and weather, this is a nice class.
*/
63 class EmberEntity : public Eris::Entity {
64 friend class EmberEntityFactory;
public:
enum MovementMode
{
MM_DEFAULT = 0,
MM_STANDING = 1,
MM_FLOATING = 2,
MM_PROJECTILE = 3,
MM_SWIMMING = 4,
MM_WALKING = 5,
MM_RUNNING = 6,
MM_FIXED = 7
};
80 static const std::string MODE_STANDING;
81 static const std::string MODE_RUNNING;
82 static const std::string MODE_WALKING;
83 static const std::string MODE_SWIMMING;
84 static const std::string MODE_FLOATING;
85 static const std::string MODE_FIXED;
/**
The material used for showing the eris bbox.
*/
90 static const std::string BboxMaterialName;
94 EmberEntity( const std::string& id, Eris::TypeInfo* ty, Eris::View* vw, Ogre::SceneManager* sceneManager );
95 virtual ~EmberEntity( );
/**
* Called by contained entites to determine how they should be adjusted, for example snap to the ground.
* For instance a house entitiy containing a player entity.
* This should of course be extended to a more dynamic physics simulation
* in the future
*/
104 virtual void adjustPositionForContainedNode( EmberEntity* const entity, const Ogre::Vector3& position );
/**
* Adjust the height of the entity so that it "snaps" to the ground.
* This is most often done by making a call to the containing node's
* adjustPositionForContainedNode method.
*/
112 virtual void adjustPosition( );
113 virtual void adjustPosition( const Ogre::Vector3& position );
/**
* return the scenenode to which this entity belongs
*/
118 Ogre::SceneNode* getSceneNode( ) const;
/**
* Called by a contained member to see if the member is allowed to be shown.
* This can be reimplemented in a subclass such as AvatarEmberEntity to
* disallow things that belongs to a characters inventory to be shown.
*/
125 virtual bool allowVisibilityOfMember( EmberEntity* entity );
/**
*return true if the entity has a list of suggested responses
*/
131 bool hasSuggestedResponses( ) const;
/**
* returns a list of all suggested responses
*/
136 const std::vector< std::string >& getSuggestedResponses( ) const;
/**
* Sets the visibity of the Entity
* @param visible
*/
143 virtual void setVisible( bool visible );
/**
* gets the location as cast to an EmberEntity
* @return
*/
150 EmberEntity* getEmberLocation( ) const;
/**
attaches the entity to another entity ( or in reality another Model )
*/
155 virtual void attachToPointOnModel( const std::string& point, Model::Model* model ) {};
/**
detaches the entity from another entity ( or in reality another Model )
*/
160 virtual void detachFromModel( ) {};
/**
if this is true, init( ... ) has been called and the entity been set up
*/
165 inline bool isInitialized( ) const;
/**
the mode the entity is in, like walking, running, swimming etc.
*/
170 inline MovementMode getMovementMode( ) const;
/**
Call this method once per frame to update the motion of the entity
*/
175 virtual void updateMotion( Ogre::Real timeSlice );
/**
For debugging.
Shows the Ogre bounding box.
*/
181 virtual void showOgreBoundingBox( bool show );
/**
For debugging.
Shows the eris/atlas bounding box.
@see mErisEntityBoundingBox
*/
189 virtual void showErisBoundingBox( bool show );
/**
returns whether the ogre bounding box is shown
*/
194 virtual bool getShowOgreBoundingBox( ) const;
/**
returns whether the eris/atlas bounding box is shown
@see mErisEntityBoundingBox
*/
200 virtual bool getShowErisBoundingBox( ) const;
/**
* returns the world bounding box of the entity
* @param derive whether to derive from attached objects too
* @return
*/
207 virtual const Ogre::AxisAlignedBox& getWorldBoundingBox( bool derive = true ) const;
210 virtual const Ogre::Sphere & getWorldBoundingSphere ( bool derive=true ) const;
/**
* Returns a list of the default use operators that can be used with this entity.
For example, an axe would have a list of operators such as "chop" and "sharpen".
* @return
*/
217 std::vector<std::string> getDefaultUseOperators( );
/**
* Synchronizes the position and orientation of the entity with the server.
*/
223 void synchronizeWithServer( );
/**
Dumps all of this entity's attributes to the supplied outstream.
*/
229 void dumpAttributes( std::iostream& outstream, std::ostream& logOutstream ) const;
/**
* General method for turning on and off debug visualizations. Subclasses might support more types of visualizations than the ones defined here.
* @param visualization The type of visualization. Currently supports "OgreBBox" and "ErisBBox".
* @param visualize Whether to visualize or not.
*/
236 virtual void setVisualize( const std::string& visualization, bool visualize );
/**
* Gets whether a certain visualization is turned on or off.
* @param visualization The type of visualization. Currently supports "OgreBBox" and "ErisBBox".
* @return true if visualization is turned on, else false
*/
244 virtual bool getVisualize( const std::string& visualization ) const;
protected:
/**
* Gets the position of a contained node.
* @param position
* @param entity
* @return
*/
255 virtual const Ogre::Vector3& getOffsetForContainedNode( const Ogre::Vector3& position, EmberEntity* const entity );
/**
if this is true, init( ... ) has been called and the entity been set up
*/
261 bool mIsInitialized;
/**
if true, the entity is already registered with the motion manager, so we don't need to add it again ( which can be expensive since
the motionmanager holds all entities needing updated motions in a std::set )
*/
267 bool mIsInMotionManager;
/**
* Overridden from Eris::Entity
* @see Eris::Entity
*/
273 virtual void onMoved( );
274 virtual void setMoving( bool moving );
275 virtual void onTalk( const Atlas::Objects::Operation::RootOperation& talk );
// virtual void setContainer( Entity *pr );
277 virtual void onVisibilityChanged( bool vis );
278 virtual void onLocationChanged( Eris::Entity *oldLocation );
279 virtual void onAction( const Atlas::Objects::Operation::RootOperation& act );
280 virtual void onImaginary( const Atlas::Objects::Root& act );
281 virtual void onSoundAction( const Atlas::Objects::Operation::RootOperation& op );
283 virtual void addArea( Terrain::TerrainArea* area );
284 virtual void onAttrChanged( const std::string& str, const Atlas::Message::Element& v );
287 virtual void onModeChanged( MovementMode newMode );
/**
* Called when the bounding box has changed.
*/
292 virtual void onBboxChanged( );
/**
For debugging purposes. This holds a bounding box of how the entity appears in the eris/atlas world.
This is often different from the Ogre bounding box.
*/
299 Ogre::OOBBWireBoundingBox* mErisEntityBoundingBox;
/**
* Creates the material used for the eris bboxes, if not already created.
*/
304 void createErisBboxMaterial( );
/**
* Creates the main scene node which holds the entity.
*/
311 void createSceneNode( Ogre::SceneManager* sceneManager );
/**
override from eris
this is called by eris just after the entity has been put into the world
*/
317 virtual void init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp );
319 virtual void checkVisibility( bool vis );
/**
Sometimes when talking to an entity, the server will provide suggested responses. These are stored here.
*/
324 std::vector<std::string> mSuggestedResponses;
/**
* The main SceneNode which holds the entity in the ogre world space.
*/
329 Ogre::SceneNode* mOgreNode;
/**
Gets the scene manager that manages the Ogre scene node held by this.
*/
334 Ogre::SceneManager* getSceneManager( );
/**
If there's a terrainarea belonging to this entity, that's stored here.
*/
339 std::auto_ptr<Terrain::TerrainArea> mTerrainArea;
/**
the mode the entity is in, like walking, running, swimming etc.
*/
MovementMode mMovementMode;
/**
* parses the current mode from the submitted element, which should be taken from the "mode" attribute
* this method will in turn call onModeChanged if the mode is changed
* @param v
*/
353 void parseModeChange( const Atlas::Message::Element& v );
};
///inline implementations
359 bool EmberEntity::isInitialized( ) const
{
return mIsInitialized;
}
364 EmberEntity::MovementMode EmberEntity::getMovementMode( ) const
{
return mMovementMode;
}
}
#endif // DIMEENTITY_H
1 //
// C++ Implementation: EmberEntityActionCreator
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "EmberEntityActionCreator.h"
#include "EmberEntityModelAction.h"
#include "EmberEntityPartAction.h"
#include "model/mapping/Cases/CaseBase.h"
using namespace EmberOgre::Model::Mapping;
namespace EmberOgre {
32 EmberEntityActionCreator::EmberEntityActionCreator( EmberPhysicalEntity& entity )
: mEntity( entity )
{
}
38 EmberEntityActionCreator::~EmberEntityActionCreator( )
{
}
42 void EmberEntityActionCreator::createActions( ModelMapping& modelMapping, Cases::CaseBase* aCase, Definitions::CaseDefinition& caseDefinition )
{
Definitions::CaseDefinition::ActionStore::iterator endJ = caseDefinition.getActions( ).end( );
for ( Definitions::CaseDefinition::ActionStore::iterator J = caseDefinition.getActions( ).begin( ); J != endJ; ++J ) {
if ( J->getType( ) == "display-part" ) {
EmberEntityPartAction* action = new EmberEntityPartAction( mEntity, J->getValue( ) );
aCase->addAction( action );
} else if ( J->getType( ) == "display-model" ) {
EmberEntityModelAction* action = new EmberEntityModelAction( mEntity, J->getValue( ) );
aCase->addAction( action );
}
}
}
}
1 //
// C++ Interface: EmberEntityActionCreator
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREEMBERENTITYACTIONCREATOR_H
#define EMBEROGREEMBERENTITYACTIONCREATOR_H
#include "EmberOgrePrerequisites.h"
#include "EmberPhysicalEntity.h"
#include "model/mapping/ModelMapping.h"
#include "model/mapping/Definitions/ModelMappingDefinition.h"
#include "model/mapping/ModelMappingManager.h"
#include "model/mapping/IActionCreator.h"
namespace EmberOgre {
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
38 class EmberEntityActionCreator : public Model::Mapping::IActionCreator
{
public:
41 EmberEntityActionCreator( EmberPhysicalEntity& entity );
43 ~EmberEntityActionCreator( );
44 virtual void createActions( Model::Mapping::ModelMapping& modelMapping, Model::Mapping::Cases::CaseBase* aCase, Model::Mapping::Definitions::CaseDefinition& caseDefinition );
protected:
46 EmberPhysicalEntity& mEntity;
};
}
#endif
/*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "EmberEntityFactory.h"
#include <Eris/Entity.h>
#include <Eris/View.h>
#include <Eris/TypeInfo.h>
#include <Eris/Avatar.h>
#include "services/server/ServerService.h"
#include "services/EmberServices.h"
#include "EmberEntity.h"
#include "WorldEmberEntity.h"
#include "EmberPhysicalEntity.h"
#include "AvatarEmberEntity.h"
#include "EmberOgre.h"
#include "model/Model.h"
#include "model/ModelDefinition.h"
#include "model/ModelDefinitionManager.h"
#include "model/mapping/EmberModelMappingManager.h"
#include "framework/ConsoleBackend.h"
#include "terrain/TerrainGenerator.h"
#include "Avatar.h"
#include "services/EmberServices.h"
#include "services/config/ConfigService.h"
#include "framework/osdir.h"
#ifdef WIN32
#include <tchar.h>
#define snprintf _snprintf
#include <io.h> // for _access, Win32 version of stat( )
#include <direct.h> // for _mkdir
// #include <sys/stat.h>
#include <iostream>
#include <fstream>
#include <ostream>
#else
#include <dirent.h>
#endif
namespace EmberOgre {
74 EmberEntityFactory::EmberEntityFactory( Eris::View* view, Terrain::TerrainGenerator* terrainGenerator, Eris::TypeService* typeService )
: ShowModels( "showmodels", this, "Show or hide models." )
76 , DumpAttributes( "dump_attributes", this, "Dumps the attributes of a supplied entity to a file. If no entity id is supplied the current avatar will be used." )
, mTerrainGenerator( terrainGenerator )
, mTypeService( typeService )
, mTerrainType( 0 )
, mWorldEntity( 0 )
, mView( view )
{
mView->registerFactory( this );
mTerrainType = mTypeService->getTypeByName( "world" );
getErisAvatar( )->GotCharacterEntity.connect( sigc::mem_fun( *this, &EmberEntityFactory::gotAvatarCharacter ) );
}
93 EmberEntityFactory::~EmberEntityFactory( )
{
/// there is no way to deregister the factory from the View, instead the View will delete the factory when deleted
// mView->deregisterFactory( this );
}
/// create whatever entity the client desires
100 Eris::Entity* EmberEntityFactory::instantiate( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View* w )
{
Eris::Entity* emberEntity( 0 );
bool isPhysical = Model::Mapping::EmberModelMappingManager::getSingleton( ).getManager( ).getDefinitionForType( type ) != 0;
if ( ge->getId( ) == getErisAvatar( )->getId( ) ) {
AvatarEmberEntity* avatarEntity = createAvatarEntity( ge, type, w );
emberEntity = avatarEntity;
} else if ( type->isA( mTerrainType ) ) {
emberEntity = createWorld( ge, type, w );
} else if ( !isPhysical ) {
S_LOG_VERBOSE( "Creating immaterial entity." );
///we don't want this to have any Ogre::Entity
emberEntity = new EmberEntity( ge->getId( ), type, w, EmberOgre::getSingleton( ).getSceneManager( ) );
} else {
emberEntity = createPhysicalEntity( ge, type, w );
}
S_LOG_VERBOSE( "Entity added to game view." );
return emberEntity;
}
132 bool EmberEntityFactory::accept( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type )
{
return true;
}
138 Eris::Entity* EmberEntityFactory::createWorld( const Atlas::Objects::Entity::RootEntity & ge, Eris::TypeInfo* type, Eris::View *world ) {
assert( !mWorldEntity );
mWorldEntity = new WorldEmberEntity( ge->getId( ), type, world, EmberOgre::getSingleton( ).getSceneManager( ), mTerrainGenerator );
return mWorldEntity;
}
144 WorldEmberEntity* EmberEntityFactory::getWorld( ) const
{
return mWorldEntity;
}
149 void EmberEntityFactory::gotAvatarCharacter( Eris::Entity* entity )
{
AvatarEmberEntity* avatarEntity = static_cast<AvatarEmberEntity*>( entity );
EmberOgre::getSingleton( ).getAvatar( )->createdAvatarEmberEntity( avatarEntity );
EmberOgre::getSingleton( ).EventCreatedAvatarEntity.emit( avatarEntity );
}
161 EmberPhysicalEntity* EmberEntityFactory::createPhysicalEntity( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View *world ) {
EmberPhysicalEntity* entity = new EmberPhysicalEntity( ge->getId( ), type, world, EmberOgre::getSingleton( ).getSceneManager( ) );
return entity;
}
169 AvatarEmberEntity* EmberEntityFactory::createAvatarEntity( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View *world )
{
return new AvatarEmberEntity( ge->getId( ), type, world, EmberOgre::getSingleton( ).getSceneManager( ), getErisAvatar( ) );
}
174 int EmberEntityFactory::priority( ) {
return 10;
}
178 Eris::Avatar* EmberEntityFactory::getErisAvatar( )
{
return mView->getAvatar( );
}
183 void EmberEntityFactory::dumpAttributesOfEntity( const std::string& entityId ) const
{
EmberEntity* entity = EmberOgre::getSingleton( ).getEmberEntity( entityId );
if ( entity ) {
///make sure the directory exists
std::string dir( Ember::EmberServices::getSingletonPtr( )->getConfigService( )->getHomeDirectory( ) + "/entityexport/" );
if ( !oslink::directory( dir ).isExisting( ) ) {
S_LOG_INFO( "Creating directory " << dir );
#ifdef __WIN32__
mkdir( dir.c_str( ) );
#else
mkdir( dir.c_str( ), S_IRWXU );
#endif
}
const std::string fileName( dir + entityId + ".atlas" );
std::fstream exportFile( fileName.c_str( ), std::fstream::out );
S_LOG_INFO( "Dumping attributes to " << fileName );
entity->dumpAttributes( exportFile, std::cout );
Ember::ConsoleBackend::getMainConsole( )->pushMessage( std::string( "Dumped attributes to " ) + fileName );
}
}
209 void EmberEntityFactory::runCommand( const std::string &command, const std::string &args )
{
if( command == ShowModels.getCommand( ) )
{
Ember::Tokeniser tokeniser;
tokeniser.initTokens( args );
std::string value = tokeniser.nextToken( );
if ( value == "true" ) {
S_LOG_INFO( "Showing models." );
Model::ModelDefinitionManager::getSingleton( ).setShowModels( true );
} else if ( value == "false" ) {
S_LOG_INFO( "Hiding models." );
Model::ModelDefinitionManager::getSingleton( ).setShowModels( false );
}
} else if ( DumpAttributes == command ) {
Ember::Tokeniser tokeniser;
tokeniser.initTokens( args );
std::string value = tokeniser.nextToken( );
if ( value == "" ) {
if ( getErisAvatar( ) ) {
dumpAttributesOfEntity( getErisAvatar( )->getEntity( )->getId( ) );
}
} else {
dumpAttributesOfEntity( value );
}
}
}
}
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DIMEENTITYFACTORY_H
#define DIMEENTITYFACTORY_H
#include "EmberOgrePrerequisites.h"
#include <Eris/Factory.h>
#include <Atlas/Objects/Entity.h>
#include <sigc++/trackable.h>
#include "framework/ConsoleObject.h"
namespace Eris
{
32 class Entity;
33 class View;
34 class TypeService;
35 class TypeInfo;
36 class Avatar;
}
namespace EmberOgre {
namespace Terrain
{
43 class TerrainGenerator;
}
class AvatarEmberEntity;
47 class EmberTerrainPageSource;
48 class EmberPhysicalEntity;
49 class EmberEntity;
50 class ViewEmberEntity;
51 class WorldEmberEntity;
/**
* Creates the EmberEntities required.
* Basically this attaches to Eris and creates Entites on demand.
* @see Eris::Factory
*
*/
59 class EmberEntityFactory :
60 public Eris::Factory,
61 public sigc::trackable,
62 public Ember::ConsoleObject
{
public:
typedef std::set<Ogre::String> StringSet;
/**
Default constructor. This should be instantiated by EmberOgre or similiar high level object. Note that Eris upon shutdown will delete all registered factories, so don't delete an instance of this yourself.
*/
72 EmberEntityFactory( Eris::View* view, Terrain::TerrainGenerator* terrainGenerator, Eris::TypeService* typeService );
73 virtual ~EmberEntityFactory( );
/**
Will always return true.
*/
78 virtual bool accept( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type );
/**
Creates instances of EmberEntity and its subclasses.
*/
83 virtual Eris::Entity* instantiate( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View* w );
/** retrieve this factory's priority level; higher priority factories
get first chance to process a recieved Atlas entity. The default implementation
returns one. */
88 virtual int priority( );
/**
Returns the main world entity.
*/
93 WorldEmberEntity* getWorld( ) const;
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
100 virtual void runCommand( const std::string &command, const std::string &args );
/**
Command for setting whether models should be shown or not.
*/
106 const Ember::ConsoleCommandWrapper ShowModels;
/**
Dumps the attributes of a supplied entity to the std::out.
*/
111 const Ember::ConsoleCommandWrapper DumpAttributes;
/**
* Dumps the attributes of the entity with the supplied id to the std::out.
* @param entityId
* @return
*/
119 void dumpAttributesOfEntity( const std::string& entityId ) const;
protected:
/**
Creates a WorldEmberEntity instance.
*/
127 Eris::Entity* createWorld( const Atlas::Objects::Entity::RootEntity & ge, Eris::TypeInfo* type, Eris::View *world );
/**
Creates a EmberPhysicalEntity instance.
*/
131 EmberPhysicalEntity* createPhysicalEntity( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View *world );
/**
Creates a AvatarEmberEntity instance.
*/
135 AvatarEmberEntity* createAvatarEntity( const Atlas::Objects::Entity::RootEntity &ge, Eris::TypeInfo* type, Eris::View *world );
137 void gotAvatarCharacter( Eris::Entity* entity );
141 Terrain::TerrainGenerator* mTerrainGenerator;
142 Eris::TypeService* mTypeService;
143 Eris::TypeInfo* mTerrainType;
145 Eris::Avatar* getErisAvatar( );
147 WorldEmberEntity *mWorldEntity;
149 Eris::View* mView;
};
}
#endif // DIMEENTITYFACTORY_H
1 //
// C++ Implementation: EmberEntityModelAction
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "EmberEntityModelAction.h"
namespace EmberOgre {
27 EmberEntityModelAction::EmberEntityModelAction( EmberPhysicalEntity& entity, std::string modelName )
: mEntity( entity ), mModelName( modelName )
{
}
33 EmberEntityModelAction::~EmberEntityModelAction( )
{
}
37 void EmberEntityModelAction::activate( )
{
mEntity.setModel( mModelName );
S_LOG_VERBOSE( "Showing model " << mModelName );
}
43 void EmberEntityModelAction::deactivate( )
{
mEntity.setModel( "" );
S_LOG_VERBOSE( "Hiding model " << mModelName );
}
}
1 //
// C++ Interface: EmberEntityModelAction
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREEMBERENTITYMODELACTION_H
#define EMBEROGREEMBERENTITYMODELACTION_H
#include "EmberOgrePrerequisites.h"
#include "EmberPhysicalEntity.h"
// #include "model/mapping/ModelMapping.h"
#include "model/mapping/Actions/Action.h"
namespace EmberOgre {
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
37 class EmberEntityModelAction : public Model::Mapping::Actions::Action
{
public:
40 EmberEntityModelAction( EmberPhysicalEntity& entity, std::string modelName );
41 ~EmberEntityModelAction( );
43 virtual void activate( );
44 virtual void deactivate( );
protected:
47 EmberPhysicalEntity& mEntity;
49 std::string mModelName;
};
}
#endif
1 //
// C++ Implementation: EmberEntityPartAction
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "EmberEntityPartAction.h"
#include "model/Model.h"
namespace EmberOgre {
32 EmberEntityPartAction::EmberEntityPartAction( EmberPhysicalEntity& entity, std::string partName )
: mEntity( entity ), mPartName( partName )
{
}
38 EmberEntityPartAction::~EmberEntityPartAction( )
{
}
42 void EmberEntityPartAction::activate( )
{
S_LOG_VERBOSE( "Showing part " << mPartName );
mEntity.showModelPart( mPartName );
// Model::Model* model = mEntity.getModel( );
// if ( model ) {
// model->showPart( mPartName );
//
// }
}
53 void EmberEntityPartAction::deactivate( )
{
S_LOG_VERBOSE( "Hiding part " << mPartName );
mEntity.hideModelPart( mPartName );
// Model::Model* model = mEntity.getModel( );
// if ( model ) {
// model->hidePart( mPartName, false );
// }
}
}
1 //
// C++ Interface: EmberEntityPartAction
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREEMBERENTITYPARTACTION_H
#define EMBEROGREEMBERENTITYPARTACTION_H
#include "EmberOgrePrerequisites.h"
#include "EmberPhysicalEntity.h"
#include "model/mapping/ModelMapping.h"
#include "model/mapping/Actions/Action.h"
namespace EmberOgre {
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
36 class EmberEntityPartAction : public Model::Mapping::Actions::Action
{
public:
39 EmberEntityPartAction( EmberPhysicalEntity& entity, std::string partName );
40 ~EmberEntityPartAction( );
42 virtual void activate( );
43 virtual void deactivate( );
protected:
46 EmberPhysicalEntity& mEntity;
48 std::string mPartName;
};
}
#endif
1 //
// C++ Implementation: EmberEntityUserObject
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "EmberEntityUserObject.h"
#include "ogreopcode/include/OgreCollisionObject.h"
#include "EmberEntity.h"
#include "model/Model.h"
namespace EmberOgre {
const Ogre::String EmberEntityUserObject::s_TypeName = "EmberEntityPickerObject";
34 EmberEntityUserObject::EmberEntityUserObject( EmberEntity* emberEntity, Model::Model* model, ICollisionDetector* collisionDetector )
: mEmberEntity( emberEntity ),
mModel( model ),
mCollisionDetector( collisionDetector )
// mCollisionObjects( collisionObjects ),
{
}
// CollisionObjectStore EmberEntityUserObject::getCollisionObjects( ) const
// {
// return mCollisionObjects;
// }
47 EmberEntityUserObject::~EmberEntityUserObject( )
{
delete mCollisionDetector;
/* OgreOpcode::CollisionContext* collideContext = OgreOpcode::CollisionManager::getSingletonPtr( )->getDefaultContext( );
for ( EmberEntityUserObject::CollisionObjectStore::iterator I = mCollisionObjects.begin( ); I != mCollisionObjects.end( ); ++I )
{
collideContext->removeObject( *I );
OgreOpcode::CollisionManager::getSingleton( ).destroyShape( ( *I )->getShape( ) );
delete *I;
}*/
}
59 void EmberEntityUserObject::refit( )
{
if ( mCollisionDetector ) {
mCollisionDetector->refit( );
}
/* for ( EmberEntityUserObject::CollisionObjectStore::iterator I = mCollisionObjects.begin( ); I != mCollisionObjects.end( ); ++I )
{
( *I )->refit( );;
}*/
}
70 EmberEntity* EmberEntityUserObject::getEmberEntity( ) const
{
return mEmberEntity;
}
75 Model::Model* EmberEntityUserObject::getModel( ) const
{
return mModel;
}
80 const Ogre::String & EmberEntityUserObject::getTypeName ( void ) const
{
return s_TypeName;
}
};
1 //
// C++ Interface: EmberEntityUserObject
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREEMBERENTITYUSEROBJECT_H
#define EMBEROGREEMBERENTITYUSEROBJECT_H
#include "EmberOgrePrerequisites.h"
namespace Ogre
{
32 class Entity;
};
namespace EmberOgre {
namespace Model {
38 class Model;
}
40 class EmberEntity;
struct CollisionResult
{
bool collided;
Ogre::Vector3 position;
Ogre::Real distance;
};
/**
@author Erik Hjortsberg
* Interface for collision detectors, responsible for determining collision information for the entity that they are attached to.
*/
55 class ICollisionDetector
{
public:
58 virtual ~ICollisionDetector( ) {};
/**
* Testa whether the provided ray hits the entity.
* @param ray The ray to test.
* @param result The result of the collision. If the ray hits, the collision detector must update this object.
*/
65 virtual void testCollision( Ogre::Ray& ray, CollisionResult& result ) = 0;
/**
* Refits the collision mesh against the entity. This is called to ensure that the collision mesh fits animated entities.
*/
69 virtual void refit( ) = 0;
/**
* Called when the entity changes, such as a subentity being hidden or shown. Implementations must reload the collision data.
*/
75 virtual void reload( ) = 0;
/**
* Sets whether the collision data should be visualized for debugging purposes.
* @param visualize
*/
81 virtual void setVisualize( bool visualize ) = 0;
/**
* Gets whether the collision data should be visualized for debugging purposes.
* @return
*/
86 virtual bool getVisualize( ) const = 0;
};
/**
@author Erik Hjortsberg
Instances of this class can be attached to scene nodes in the ogre system. They will allow for the Ember system to be accessed directly from Ogre, without having to do lookups.
This is generally mostly used for mouse picking and collision handling.
*/
98 class EmberEntityUserObject : public Ogre::UserDefinedObject
{
public:
/**
The type of UserDefinedObject
*/
105 static const std::string s_TypeName;
// typedef std::vector<OgreOpcode::CollisionObject*> CollisionObjectStore;
/**
* Constructor.
* @param emberEntity A valid EmberEntity instance.
* @param model A valid Model instance.
* @param collisionObject A valid vector of collision objects.
* @return
*/
115 EmberEntityUserObject( EmberEntity* emberEntity, Model::Model* model, ICollisionDetector* collisionDetector );
117 virtual ~EmberEntityUserObject( );
/**
* Gets the EmberEntity contained.
* @return
*/
123 EmberEntity* getEmberEntity( ) const;
/**
* Gets the Model instance.
* @return
*/
129 Model::Model* getModel( ) const ;
/**
* Gets a pointer to a vector of CollisionObjects. This can be used for checking collisions.
* @return
*/
// CollisionObjectStore* getCollisionObjects( ) { return &mCollisionObjects; }
/**
* Overloaded method for getting the type name of this instance.
* @param
* @return
*/
142 virtual const Ogre::String & getTypeName ( void ) const;
144 void refit( );
146 inline ICollisionDetector* getCollisionDetector( ) const;
private:
149 EmberEntity* mEmberEntity;
150 Model::Model* mModel;
//CollisionObjectStore mCollisionObjects;
152 ICollisionDetector* mCollisionDetector;
};
156 ICollisionDetector* EmberEntityUserObject::getCollisionDetector( ) const
{
return mCollisionDetector;
}
};
#endif
1 /*
-----------------------------------------------------------------------------
OgreApp.cpp by Miguel Guzman Miranda ( Aglanor )
Based on OGRE sample applications:
OGRE ( Object-oriented Graphics Rendering Engine )
For the latest info, see http://ogre.sourceforge.net
Based on the Ember main application by the Ember team
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 2 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, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
-----------------------------------------------------------------------------
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "EmberOgre.h"
// Headers to stop compile problems from headers
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef WIN32
#include <tchar.h>
#define snprintf _snprintf
#include <io.h> // for _access, Win32 version of stat( )
#include <direct.h> // for _mkdir
// #include <sys/stat.h>
#include <iostream>
#include <fstream>
#include <ostream>
#else
#include <dirent.h>
#endif
#include "EmberOgrePrerequisites.h"
// ------------------------------
// Include Eris header files
// ------------------------------
/*#include <Eris/PollDefault.h>*/
#include <Eris/Connection.h>
#include <Eris/View.h>
//Ember headers
#include "services/EmberServices.h"
#include "services/logging/LoggingService.h"
#include "services/server/ServerService.h"
#include "services/config/ConfigService.h"
#include "services/metaserver/MetaserverService.h"
#include "services/sound/SoundService.h"
#include "services/scripting/ScriptingService.h"
#include "services/wfut/WfutService.h"
#include "framework/ConsoleBackend.h"
#include "framework/ConsoleObject.h" //TODO: this will be included in a different class
#include "framework/binreloc.h" //this is needed for binreloc functionality
// ------------------------------
// Include OGRE Ember client files
// ------------------------------
#include "terrain/TerrainGenerator.h"
#include "terrain/TerrainLayerDefinitionManager.h"
#include "ConsoleObjectImpl.h"
#include "Avatar.h"
#include "AvatarController.h"
#include "EmberEntityFactory.h"
#include "MotionManager.h"
#include "AvatarCamera.h"
#include "GUIManager.h"
#include "manipulation/EntityMoveManager.h"
#include "EmberEntity.h"
#include "WorldEmberEntity.h"
#include "environment/meshtree/TParameters.h"
#include "environment/Tree.h"
#include "carpenter/Carpenter.h"
#include "carpenter/BluePrint.h"
#include <OgreSceneManager.h>
#include "SceneManagers/EmberPagingSceneManager/include/EmberPagingSceneManager.h"
#include "SceneManagers/EmberPagingSceneManager/include/EmberPagingSceneManagerAdapter.h"
#include "model/ModelDefinitionManager.h"
#include "model/ModelDefinition.h"
#include "model/mapping/EmberModelMappingManager.h"
#include "ogreopcode/include/OgreCollisionManager.h"
#include "OpcodeCollisionDetectorVisualizer.h"
// ------------------------------
// Include Ember header files
// ------------------------------
#include "framework/ConsoleBackend.h"
#include "jesus/Jesus.h"
#include "jesus/XMLJesusSerializer.h"
#include "framework/osdir.h"
#include "framework/Exception.h"
#include "OgreLogObserver.h"
#include "OgreResourceLoader.h"
#include "widgets/LoadingBar.h"
#include "sound/OgreSoundProvider.h"
#include "OgreSetup.h"
#include "manipulation/MaterialEditor.h"
#include "MediaUpdater.h"
#include "main/Application.h"
#include "input/InputCommandMapper.h"
#include "input/Input.h"
#include "OgreResourceProvider.h"
#include "scripting/LuaScriptingProvider.h"
template<> EmberOgre::EmberOgre* Ember::Singleton<EmberOgre::EmberOgre>::ms_Singleton = 0;
namespace EmberOgre {
152 void assureConfigFile( const std::string& filename, const std::string& originalConfigFileDir )
{
struct stat tagStat;
int ret = stat( filename.c_str( ), &tagStat );
if ( ret == -1 ) {
ret = stat( ( originalConfigFileDir +filename ).c_str( ), &tagStat );
if ( ret == 0 ) {
///copy conf file from shared
std::ifstream instream ( ( originalConfigFileDir + filename ).c_str( ) );
std::ofstream outstream ( filename.c_str( ) );
outstream << instream.rdbuf( );
}
}
}
169 EmberOgre::EmberOgre( ) :
mAvatar( 0 ),
mAvatarController( 0 ),
mRoot( 0 ),
mSceneMgr( 0 ),
mWindow( 0 ),
mInput( std::auto_ptr<Input>( new Input ) ),
mGeneralCommandMapper( std::auto_ptr<InputCommandMapper>( new InputCommandMapper( "general" ) ) ),
mEmberEntityFactory( 0 ),
mTerrainGenerator( 0 ),
mMotionManager( 0 ),
mGUIManager( 0 ),
mModelDefinitionManager( 0 ),
mModelMappingManager( 0 ),
mTerrainLayerManager( 0 ),
mMoveManager( 0 ),
mKeepOnRunning( true ),
mJesus( 0 ),
mLogObserver( 0 ),
mMaterialEditor( 0 ),
mCollisionManager( 0 ),
mCollisionDetectorVisualizer( 0 )
{
Ember::Application::getSingleton( ).EventServicesInitialized.connect( sigc::mem_fun( *this, &EmberOgre::Application_ServicesInitialized ) );
}
195 EmberOgre::~EmberOgre( )
{
delete mCollisionDetectorVisualizer;
delete mCollisionManager;
delete mMaterialEditor;
delete mJesus;
delete mMoveManager;
///The factory will be deleted by the mWorldView when that is deleted later on, so we shall not delete it here
// delete mEmberEntityFactory;
delete mAvatarController;
delete mAvatar;
///start with deleting the eris world, then shut down ogre
// delete mWorldView;
delete mMotionManager;
delete mTerrainGenerator;
delete mGUIManager;
delete mTerrainLayerManager;
delete mModelMappingManager;
///we need to make sure that all Models are destroyed before Ogre begins destroying other movable objects ( such as Entities )
///this is because Model internally uses Entities, so if those Entities are destroyed by Ogre before the Models are destroyed, the Models will try to delete them again, causing segfaults and other wickedness
///by deleting the model manager we'll assure that
delete mModelDefinitionManager;
if ( mWindow ) {
mRoot->detachRenderTarget( mWindow );
}
Ogre::LogManager::getSingleton( ).getDefaultLog( )->removeListener( mLogObserver );
delete mLogObserver;
if ( mOgreSetup.get( ) ) {
mOgreSetup->shutdown( );
mOgreSetup.release( );
}
/* delete mOgreResourceLoader;
// mSceneMgr->shutdown( );
// delete mWorldView;
//mSceneMgr->removeAllCameras( );
// mSceneMgr->clearScene( );
delete mGUIManager;
delete mTerrainGenerator;
delete mMotionManager;
// if ( mAvatar )
// delete mAvatar;
delete mAvatarController;*/
// delete mModelDefinitionManager;
/* if ( mEmberEntityFactory )
delete mEmberEntityFactory;*/
// delete mRoot;
}
259 bool EmberOgre::frameEnded( const Ogre::FrameEvent & evt )
{
return true;
}
264 bool EmberOgre::frameStarted( const Ogre::FrameEvent & evt )
{
//OgreOpcode::CollisionManager::getSingletonPtr( )->getDefaultContext( )->visualize( true, false, false, false, true, true );
// if ( !mKeepOnRunning )
// S_LOG_INFO( "Shutting down Ember." );
// return mKeepOnRunning;
return true;
}
273 bool EmberOgre::renderOneFrame( )
{
mInput->processInput( );
if ( mInput->isApplicationVisible( ) ) {
return mRoot->renderOneFrame( );
}
return true;
}
282 void EmberOgre::shutdownGui( )
{
delete mGUIManager;
mGUIManager = 0;
}
288 void EmberOgre::go( )
{
if ( !setup( ) )
return;
}
// These internal methods package up the stages in the startup process
/** Sets up the application - returns false if the user chooses to abandon configuration. */
298 bool EmberOgre::setup( )
{
S_LOG_INFO( "Compiled against ogre version " << OGRE_VERSION );
Ember::ConfigService* configSrv = Ember::EmberServices::getSingleton( ).getConfigService( );
checkForConfigFiles( );
///Create a setup object through which we will start up Ogre.
mOgreSetup = std::auto_ptr<OgreSetup>( new OgreSetup );
mLogObserver = new OgreLogObserver( );
///if we do this we will override the automatic creation of a LogManager and can thus route all logging from ogre to the ember log
new Ogre::LogManager( );
Ogre::LogManager::getSingleton( ).createLog( "Ogre", true, false, true );
Ogre::LogManager::getSingleton( ).getDefaultLog( )->addListener( mLogObserver );
///We need a root object.
mRoot = mOgreSetup->createOgreSystem( );
if ( !mRoot ) {
throw Ember::Exception( "There was a problem setting up the Ogre environment, aborting." );
}
///Create the model definition manager
mModelDefinitionManager = new Model::ModelDefinitionManager( );
mModelMappingManager = new Model::Mapping::EmberModelMappingManager( );
mTerrainLayerManager = new Terrain::TerrainLayerDefinitionManager( );
///Create a resource loader which loads all the resources we need.
OgreResourceLoader ogreResourceLoader;
ogreResourceLoader.initialize( );
///check if we should preload the media
bool preloadMedia = configSrv->itemExists( "media", "preloadmedia" ) && ( bool )configSrv->getValue( "media", "preloadmedia" );
bool useWfut = configSrv->itemExists( "wfut", "enabled" ) && ( bool )configSrv->getValue( "wfut", "enabled" );
bool carryOn = mOgreSetup->configure( );
if ( !carryOn ) return false;
mWindow = mOgreSetup->getRenderWindow( );
///start with the bootstrap resources, after those are loaded we can show the LoadingBar
ogreResourceLoader.loadBootstrap( );
mSceneMgr = mOgreSetup->chooseSceneManager( );
///create the main camera, we will of course have a couple of different cameras, but this will be the main one
Ogre::Camera* camera = mSceneMgr->createCamera( "MainCamera" );
Ogre::Viewport* viewPort = mWindow->addViewport( camera );
///set the background colour to black
viewPort->setBackgroundColour( Ogre::ColourValue( 0, 0, 0 ) );
camera->setAspectRatio( Ogre::Real( viewPort->getActualWidth( ) ) / Ogre::Real( viewPort->getActualHeight( ) ) );
///The input object must know the resoluton of the screen
unsigned int height, width, depth;
int top, left;
mWindow->getMetrics( width, height, depth, left, top );
mInput->initialize( width, height );
///bind general commands
mGeneralCommandMapper->readFromConfigSection( "key_bindings_general" );
mGeneralCommandMapper->bindToInput( *mInput );
///we need a nice loading bar to show the user how far the setup has progressed
Gui::LoadingBar loadingBar;
Gui::LoadingBarSection wfutSection( loadingBar, 0.2, "Media update" );
loadingBar.addSection( &wfutSection );
Gui::WfutLoadingBarSection wfutLoadingBarSection( wfutSection );
Gui::LoadingBarSection resourceGroupSection( loadingBar, 0.8, "Resource loading" );
loadingBar.addSection( &resourceGroupSection );
unsigned int numberOfSections = ogreResourceLoader.numberOfSections( ) - 1; ///remove bootstrap since that's already loaded
Gui::ResourceGroupLoadingBarSection resourceGroupSectionListener( resourceGroupSection, numberOfSections, ( preloadMedia ? numberOfSections : 0 ), 0.7 );
loadingBar.start( mWindow );
loadingBar.setVersionText( std::string( "Version " ) + VERSION );
/// Turn off rendering of everything except overlays
mSceneMgr->clearSpecialCaseRenderQueues( );
mSceneMgr->addSpecialCaseRenderQueue( Ogre::RENDER_QUEUE_OVERLAY );
mSceneMgr->setSpecialCaseRenderQueueMode( Ogre::SceneManager::SCRQM_INCLUDE );
if ( useWfut ) {
S_LOG_INFO( "Updating media." );
MediaUpdater updater;
updater.performUpdate( );
}
///create the collision manager
mCollisionManager = new OgreOpcode::CollisionManager( mSceneMgr );
mCollisionDetectorVisualizer = new OpcodeCollisionDetectorVisualizer( );
ogreResourceLoader.loadGui( );
ogreResourceLoader.loadGeneral( );
///add ourself as a frame listener
Ogre::Root::getSingleton( ).addFrameListener( this );
///should media be preloaded?
if ( preloadMedia )
{
S_LOG_INFO( "Begin preload." );
ogreResourceLoader.preloadMedia( );
S_LOG_INFO( "End preload." );
}
try {
mGUIManager = new GUIManager( mWindow, mSceneMgr );
EventGUIManagerCreated.emit( *mGUIManager );
} catch ( ... ) {
///we failed at creating a gui, abort ( since the user could be running in full screen mode and could have some trouble shutting down )
throw Ember::Exception( "Could not load gui, aborting. Make sure that all media got downloaded and installed correctly." );
}
if ( chdir( configSrv->getHomeDirectory( ).c_str( ) ) ) {
S_LOG_WARNING( "Failed to change directory to '"<< configSrv->getHomeDirectory( ) << "'" );
}
// Avatar
mAvatar = new Avatar( );
mAvatarController = new AvatarController( mAvatar, mWindow, mGUIManager, camera );
EventAvatarControllerCreated.emit( *mAvatarController );
mTerrainGenerator = new Terrain::TerrainGenerator( new EmberPagingSceneManagerAdapter( mSceneMgr ) );
EventTerrainGeneratorCreated.emit( *mTerrainGenerator );
mMotionManager = new MotionManager( );
// mMotionManager->setTerrainGenerator( mTerrainGenerator );
EventMotionManagerCreated.emit( *mMotionManager );
// mSceneMgr->setPrimaryCamera( mAvatar->getAvatarCamera( )->getCamera( ) );
mMoveManager = new EntityMoveManager( );
mRoot->addFrameListener( mMotionManager );
new ConsoleObjectImpl( );
try {
mGUIManager->initialize( );
EventGUIManagerInitialized.emit( *mGUIManager );
} catch ( ... ) {
///we failed at creating a gui, abort ( since the user could be running in full screen mode and could have some trouble shutting down )
throw Ember::Exception( "Could not initialize gui, aborting. Make sure that all media got downloaded and installed correctly." );
}
/// Create the scene
createScene( );
EventSceneCreated.emit( );
///this should be in a separate class, a separate plugin even
///disable for now, since it's not used
//setupJesus( );
/// Back to full rendering
mSceneMgr->clearSpecialCaseRenderQueues( );
mSceneMgr->setSpecialCaseRenderQueueMode( Ogre::SceneManager::SCRQM_EXCLUDE );
mMaterialEditor = new MaterialEditor( );
loadingBar.finish( );
return true;
}
476 EmberEntity* EmberOgre::getEmberEntity( const std::string & eid )
{
assert( getMainView( ) );
return static_cast<EmberEntity*>( getMainView( )->getEntity( eid ) );
}
483 void EmberOgre::checkForConfigFiles( )
{
if ( chdir( Ember::EmberServices::getSingleton( ).getConfigService( )->getHomeDirectory( ).c_str( ) ) ) {
S_LOG_WARNING( "Failed to change directory to '"<< Ember::EmberServices::getSingleton( ).getConfigService( )->getHomeDirectory( ) << "', will not copy config files." );
return;
}
const std::string& sharePath( Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedConfigDirectory( ) );
///make sure that there are files
assureConfigFile( "ogre.cfg", sharePath );
//assureConfigFile( "plugins.cfg", sharePath );
}
498 void EmberOgre::preloadMedia( void )
{
Ogre::ResourceGroupManager::getSingleton( ).initialiseAllResourceGroups( );
Ember::ConfigService* configSrv = Ember::EmberServices::getSingleton( ).getConfigService( );
std::vector<std::string> shaderTextures;
shaderTextures.push_back( std::string( configSrv->getValue( "shadertextures", "rock" ) ) );
shaderTextures.push_back( std::string( configSrv->getValue( "shadertextures", "sand" ) ) );
shaderTextures.push_back( std::string( configSrv->getValue( "shadertextures", "grass" ) ) );
for ( std::vector<std::string>::iterator I = shaderTextures.begin( ); I != shaderTextures.end( ); ++I ) {
try {
Ogre::TextureManager::getSingleton( ).load( *I, "General" );
} catch ( const Ogre::Exception& e ) {
S_LOG_FAILURE( "Error when loading texture " << *I << ".\n\rError message: " << e.getDescription( ) );
}
}
//only autogenerate trees if we're not using the pregenerated ones
if ( configSrv->itemExists( "tree", "usedynamictrees" ) && ( ( bool )configSrv->getValue( "tree", "usedynamictrees" ) ) ) {
Environment::Tree tree;
tree.makeMesh( "GeneratedTrees/European_Larch", Ogre::TParameters::European_Larch );
tree.makeMesh( "GeneratedTrees/Fir", Ogre::TParameters::Fir );
}
}
531 void EmberOgre::setupJesus( )
{
const std::string datadir = Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedDataDirectory( );
Carpenter::Carpenter* carpenter = new Carpenter::Carpenter( );
mJesus = new Jesus( carpenter );
XMLJesusSerializer serializer( mJesus );
std::string dir( Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedDataDirectory( ) + "carpenter/blockspec" );
std::string filename;
//oslink::directory needs to be destroyed before a new one can be used, regular copy constructor doesn't seem to work
//we could also use new/delete, but scopes works as well
{
oslink::directory osdir( dir );
while ( osdir ) {
filename = osdir.next( );
S_LOG_VERBOSE( "Loading blockspec: " << filename );
serializer.loadBlockSpec( dir + "/" + filename );
}
}
//load all buildingblockspecs
dir = Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedDataDirectory( ) + "carpenter/modelblockspecs";
{
oslink::directory osdir( dir );
while ( osdir ) {
filename = osdir.next( );
S_LOG_VERBOSE( "Loading buildingblockspecC: " << filename );
serializer.loadBuildingBlockSpecDefinition( dir + "/" + filename );
}
}
//load all modelmappings
dir = Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedDataDirectory( ) + "jesus/modelmappings";
{
oslink::directory osdir( dir );
while ( osdir ) {
filename = osdir.next( );
S_LOG_VERBOSE( "Loading modelmapping: " << filename );
serializer.loadModelBlockMapping( dir + "/" + filename );
}
}
//load all global blueprints
dir = Ember::EmberServices::getSingleton( ).getConfigService( )->getSharedDataDirectory( ) + "carpenter/blueprints";
{
oslink::directory osdir( dir );
while ( osdir ) {
filename = osdir.next( );
S_LOG_VERBOSE( "Loading blueprint: " << filename );
Carpenter::BluePrint* blueprint = serializer.loadBlueprint( dir + "/" + filename );
if ( blueprint ) {
blueprint->compile( );
bool result = mJesus->addBluePrint( blueprint );
if ( !result )
{
S_LOG_FAILURE( "Could not add blueprint: " << filename );
}
}
}
}
//load all local blueprints
dir = Ember::EmberServices::getSingleton( ).getConfigService( )->getHomeDirectory( ) + "carpenter/blueprints";
{
oslink::directory osdir( dir );
while ( osdir ) {
filename = osdir.next( );
S_LOG_VERBOSE( "Loading local blueprint: " << filename );
Carpenter::BluePrint* blueprint = serializer.loadBlueprint( dir + "/" + filename );
if ( blueprint ) {
blueprint->compile( );
bool result = mJesus->addBluePrint( blueprint );
if ( !result )
{
S_LOG_FAILURE( "Could not add blueprint: " << filename );
}
}
}
}
EventCreatedJesus.emit( mJesus );
}
615 void EmberOgre::createScene( void )
{
///initially, while in the "void", we'll use a clear ambient light
mSceneMgr->setAmbientLight( Ogre::ColourValue( 1, 1, 1 ) );
}
623 void EmberOgre::Server_GotView( Eris::View* view )
{
// mWorldView = view;
mEmberEntityFactory = new EmberEntityFactory( view, mTerrainGenerator, Ember::EmberServices::getSingleton( ).getServerService( )->getConnection( )->getTypeService( ) );
}
629 EmberEntity* EmberOgre::getEntity( const std::string & id )
{
///this of course relies upon all entities being created by our factory
return static_cast<EmberEntity*>( getMainView( )->getEntity( id ) );
}
636 void EmberOgre::connectedToServer( Eris::Connection* connection )
{
//EventCreatedAvatarEntity.connect( sigc::mem_fun( *mAvatar, &Avatar::createdAvatarEmberEntity ) );
EventCreatedEmberEntityFactory.emit( mEmberEntityFactory );
}
644 Avatar* EmberOgre::getAvatar( ) const {
return mAvatar;
}
649 Ogre::SceneManager* EmberOgre::getSceneManager( ) const
{
return mSceneMgr;
}
654 Terrain::TerrainGenerator* EmberOgre::getTerrainGenerator( ) const
{
return mTerrainGenerator;
}
659 MotionManager* EmberOgre::getMotionManager( ) const
{
return mMotionManager;
}
664 Ogre::Root* EmberOgre::getOgreRoot( ) const
{
assert( mRoot );
return mRoot;
}
670 Ogre::SceneNode * EmberOgre::getWorldSceneNode( ) const
{
if ( mEmberEntityFactory && mEmberEntityFactory->getWorld( ) ) {
return mEmberEntityFactory->getWorld( )->getSceneNode( );
} else {
return mSceneMgr->getRootSceneNode( );
}
/* Ogre::SceneNode* node = mSceneMgr->getSceneNode( "0" );
//TODO: implement better exception handling
if ( node == 0 )
throw Exception( );
return node;*/
}
684 Ogre::SceneNode* EmberOgre::getRootSceneNode( ) const
{
return mSceneMgr->getRootSceneNode( );
}
690 AvatarCamera* EmberOgre::getMainCamera( ) const
{
return mAvatar->getAvatarCamera( );
}
695 EmberEntityFactory* EmberOgre::getEntityFactory( ) const
{
return mEmberEntityFactory;
}
700 AvatarController* EmberOgre::getAvatarController( ) const
{
return mAvatarController;
}
// // void EmberOgre::setErisPolling( bool doPoll )
// // {
// // mPollEris = doPoll;
// // }
// //
// // bool EmberOgre::getErisPolling( ) const
// // {
// // return mPollEris;
// // }
716 void EmberOgre::initializeEmberServices( const std::string& prefix, const std::string& homeDir )
{
}
721 void EmberOgre::Application_ServicesInitialized( )
{
Ember::EmberServices::getSingleton( ).getServerService( )->GotConnection.connect( sigc::mem_fun( *this, &EmberOgre::connectedToServer ) );
Ember::EmberServices::getSingleton( ).getServerService( )->GotView.connect( sigc::mem_fun( *this, &EmberOgre::Server_GotView ) );
mScriptingResourceProvider = std::auto_ptr<OgreResourceProvider>( new OgreResourceProvider( "Scripting" ) );
Ember::EmberServices::getSingleton( ).getScriptingService( )->setResourceProvider( mScriptingResourceProvider.get( ) );
///register the lua scripting provider
Ember::EmberServices::getSingleton( ).getScriptingService( )->registerScriptingProvider( new LuaScriptingProvider( ) );
}
733 Eris::View* EmberOgre::getMainView( )
{
return Ember::Application::getSingleton( ).getMainView( );
}
}
1 /*
-----------------------------------------------------------------------------
This source file is part of OGRE
( Object-oriented Graphics Rendering Engine )
For the latest info, see http://ogre.sourceforge.net/
Copyright � 2000-2002 The OGRE Team
Also see acknowledgements in Readme.html
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 2 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, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
*/
#ifndef __EmberOgre_H__
#define __EmberOgre_H__
#include "EmberOgrePrerequisites.h"
// ------------------------------
// Include sigc header files
// ------------------------------
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
#include "framework/Singleton.h"
namespace Eris {
42 class View;
43 class Connection;
}
namespace Carpenter
{
48 class Carpenter;
49 class BluePrint;
}
52 namespace Ember
{
class StreamLogObserver;
}
namespace OgreOpcode {
58 class CollisionManager;
}
61 namespace EmberOgre {
namespace Terrain
{
class TerrainGenerator;
class TerrainLayerDefinitionManager;
}
namespace Model {
class ModelDefinitionManager;
namespace Mapping {
class EmberModelMappingManager;
}
}
class CameraRotator;
class CameraFrameListener;
class Avatar;
class AvatarCamera;
class AvatarController;
class AvatarEmberEntity;
class EmberEntityFactory;
class EmberPagingSceneManager;
class MotionManager;
class Input;
class InputManager;
class InputCommandMapper;
class GUIManager;
class Jesus;
class EmberEntity;
class OgreResourceLoader;
class OgreLogObserver;
class EntityMoveManager;
class MaterialEditor;
class OgreSetup;
class OgreResourceProvider;
class OpcodeCollisionDetectorVisualizer;
/**
The main class of ember. This functions as a hub for almost all subsystems. ( Perhaps this should be refactored? )
*/
class EmberOgre : public Ember::Singleton<EmberOgre>,
public sigc::trackable,
public Ogre::FrameListener
{
public:
/// Standard constructor
EmberOgre( );
/// Standard destructor
~EmberOgre( );
virtual bool frameStarted( const Ogre::FrameEvent & evt );
virtual bool frameEnded( const Ogre::FrameEvent & evt );
/**
* starts the main app
*/
virtual void go( );
// void shutdown( );
/**
* Initialize all Ember services needed for this application
* @param the prefix for the application, not appliable if running under win32
* @param the an alternative home directory. If the default should be used, send an empty string.
*/
void initializeEmberServices( const std::string& prefix, const std::string& homeDir );
void Server_GotView( Eris::View* world );
void connectedToServer( Eris::Connection* connection );
// TODO: possibly we'd like to do the following in a different way,
// perhaps refactoring stuff
Avatar* getAvatar( ) const;
Ogre::SceneManager* getSceneManager( ) const;
Terrain::TerrainGenerator* getTerrainGenerator( ) const;
MotionManager* getMotionManager( ) const;
Ogre::Root* getOgreRoot( ) const;
EmberEntityFactory* getEntityFactory( ) const;
AvatarCamera* getMainCamera( ) const;
AvatarController* getAvatarController( ) const;
inline EntityMoveManager* getMoveManager( ) const;
// inline Input& getInput( );
/**
* Gets the entity with the supplies id from the world.
*/
EmberEntity* getEmberEntity( const std::string & eid );
inline Jesus* getJesus( ) const;
inline Ogre::RenderWindow* getRenderWindow( ) const;
sigc::signal<void, EmberEntityFactory*> EventCreatedEmberEntityFactory;
sigc::signal<void, AvatarEmberEntity*> EventCreatedAvatarEntity;
sigc::signal<void, Jesus*> EventCreatedJesus;
/**
Emitted before the eris polling is started
*/
// sigc::signal<void> EventStartErisPoll;
/**
Emitted after the eris polling has finished
*/
// sigc::signal<void> EventEndErisPoll;
/**
* returns the scenenode of the world entity
* throws en exception if no such node has been created
* @return
*/
Ogre::SceneNode* getWorldSceneNode( ) const;
/**
* returns the root scene node
* @return
*/
Ogre::SceneNode* getRootSceneNode( ) const;
/**
Emitted after the GUIManager has been created, but not yet initialized
*/
sigc::signal<void, GUIManager&> EventGUIManagerCreated;
/**
Emitted after the GUIManager has been initilized
*/
sigc::signal<void, GUIManager&> EventGUIManagerInitialized;
/**
Emitted after the Motion has been created
*/
sigc::signal<void, MotionManager&> EventMotionManagerCreated;
/**
Emitted after the TerrainGenerator has been created
*/
sigc::signal<void, Terrain::TerrainGenerator&> EventTerrainGeneratorCreated;
/**
Emitted after the AvatarController has been created
*/
sigc::signal<void, AvatarController&> EventAvatarControllerCreated;
/**
Emitted after the base Ogre scene has been created
*/
sigc::signal<void> EventSceneCreated;
EmberEntity* getEntity( const std::string & id );
/**
* Call this to "soft quit" the app. This means that an signal will be emitted, which hopefully will be taken care of by some widget, which will show a confirmation window, asking the user if he/she wants to quit.
However, if there is no widget etc. handling the request, the application will instantly quit.
*/
// void requestQuit( );
/**
* Sets whether eris should be polled each frame. Defaults to true.
* @param doPoll
*/
// void setErisPolling( bool doPoll );
/**
* Gets whether eris should be polled each frame.
* @return
*/
// bool getErisPolling( ) const;
/**
Renders one frame.
*/
bool renderOneFrame( );
/**
* Sets up the application - returns false if the user chooses to abandon configuration.
* @return
*/
bool setup( );
void shutdownGui( );
protected:
/**
utility object for setting up and tearing down ogre
*/
std::auto_ptr<OgreSetup> mOgreSetup;
Eris::View* getMainView( );
/**
* The main user avatar
*/
Avatar* mAvatar;
/**
When connected to a world, handles the avatar and patches mouse and keyboard movement events on the avatar.
*/
AvatarController* mAvatarController;
/**
The main Ogre root object. All of Ogre is accessed through this.
*/
Ogre::Root *mRoot;
/**
The main scene manager of the world.
*/
EmberPagingSceneManager* mSceneMgr;
/**
The main render window. There can be many more render targets in the system, but they will all reside within this render window ( such as entity preview through CEGUI ).
*/
Ogre::RenderWindow* mWindow;
/**
The main input object.
*/
std::auto_ptr<Input> mInput;
/**
An InputCommandMapper that will handle all general input events.
*/
std::auto_ptr<InputCommandMapper> mGeneralCommandMapper;
/**
Main factory for all entities created in the world.
*/
EmberEntityFactory* mEmberEntityFactory;
/**
* Creates the basic scene with a single avatar, just for testing purpose.
* NOTE: remove this when going final
* @param
*/
void createScene( void );
/**
* Sets up Jesus. This inialized the mJesus member and loads all building blocks, blueprint and modelblocks etc.
*/
void setupJesus( );
/**
* Preloads the media, thus avoiding frame rate drops ingame.
* @param
*/
void preloadMedia( void );
/**
makes sure that there are files in ~/.ember
*/
void checkForConfigFiles( );
/**
Responsible for handling of terrain.
*/
Terrain::TerrainGenerator* mTerrainGenerator;
/**
Responsible for updating motions and animations of entities.
*/
MotionManager* mMotionManager;
/**
Responsible for the GUI.
*/
GUIManager* mGUIManager;
/**
Resonsible for managing all Model definitions;
*/
Model::ModelDefinitionManager* mModelDefinitionManager;
/**
Handles all model mappings.
*/
Model::Mapping::EmberModelMappingManager* mModelMappingManager;
Terrain::TerrainLayerDefinitionManager* mTerrainLayerManager;
/**
Responsible for allowing movement of entities in the world by the user.
*/
EntityMoveManager* mMoveManager;
/**
when this is false the app will exit
*/
bool mKeepOnRunning;
/**
main entry point for the Jesus system ( which is an Ember wrapper for the Carpenter lib )
*/
Jesus* mJesus;
/**
Once connected to a world, this will hold the main world view.
*/
// Eris::View* mWorldView;
/**
Controls whether eris should be polled at each frame update.
*/
// bool mPollEris;
/**
The main log observer used for all logging. This will send Ogre logging events on to the internal Ember logging framework.
*/
OgreLogObserver* mLogObserver;
/**
Patches logging events from the Ember logging framework on to a file writer.
*/
// Ember::StreamLogObserver* mStreamLogObserver;
/**
Helper object that allows for easy Ogre material editing.
*/
MaterialEditor* mMaterialEditor;
void Application_ServicesInitialized( );
std::auto_ptr<OgreResourceProvider> mScriptingResourceProvider;
OgreOpcode::CollisionManager* mCollisionManager;
OpcodeCollisionDetectorVisualizer* mCollisionDetectorVisualizer;
};
// Input& EmberOgre::getInput( )
// {
// return mInput;
// }
EntityMoveManager* EmberOgre::getMoveManager( ) const
{
return mMoveManager;
}
Jesus* EmberOgre::getJesus( ) const
{
return mJesus;
}
Ogre::RenderWindow* EmberOgre::getRenderWindow( ) const
{
return mWindow;
}
}
#endif
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __EmberPrerequisites_H__
#define __EmberPrerequisites_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "OgreIncludes.h"
// #include "MathConverter.h"
///include the Logging service, since we want logging available from most classes
///in most cases, use the S_LOG* defines
///such as:
///S_LOG_INFO( "some info" )
#include "services/logging/LoggingService.h"
#include "framework/Exception.h"
///utility defines for stl containers
///for example:
///TYPEDEF_STL_VECTOR( std::string, StringVector )
///defines a new type called StringVector
///you can then use StringVector::iterator etc..
#define TYPEDEF_STL_MKITERATORS( name ) \
typedef name::iterator name##Iter; \
typedef name::const_iterator name##CIter; \
typedef name::reverse_iterator name##RIter; \
typedef name::const_reverse_iterator name##CRIter
#define TYPEDEF_STL_CONTAINER1( container, tp, name ) \
typedef std::container<tp> name; \
TYPEDEF_STL_MKITERATORS( name )
#define TYPEDEF_STL_CONTAINER2( container, tp1, tp2, name ) \
typedef std::container<tp1, tp2> name; \
TYPEDEF_STL_MKITERATORS( name )
#define TYPEDEF_STL_VECTOR( tp, name ) TYPEDEF_STL_CONTAINER1( vector, tp, name )
#define TYPEDEF_STL_LIST( tp, name ) TYPEDEF_STL_CONTAINER1( list, tp, name )
#define TYPEDEF_STL_SET( tp, name ) TYPEDEF_STL_CONTAINER1( set, tp, name )
#define TYPEDEF_STL_MAP( tpkey, tpval, name ) TYPEDEF_STL_CONTAINER2( map, tpkey, tpval, name )
typedef unsigned int uint;
#endif
1 /*
Copyright ( C ) 2004 Erik Hjortsberg
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "EmberPhysicalEntity.h"
#include "framework/ConsoleBackend.h"
#include "MotionManager.h"
#include "model/Model.h"
#include "model/ModelDefinition.h"
#include "model/SubModel.h"
#include "model/ParticleSystemBinding.h"
#include "model/Action.h"
#include "model/mapping/EmberModelMappingManager.h"
#include "model/mapping/ModelMapping.h"
#include "model/mapping/ModelMappingManager.h"
#include "environment/Environment.h"
#include "environment/Forest.h"
#include "EmberEntityFactory.h"
#include "WorldEmberEntity.h"
#include "EmberEntityActionCreator.h"
#include <OgreException.h>
#include "EmberOgre.h"
#include "MousePicker.h"
#include "EmberEntityUserObject.h"
#include "OpcodeCollisionDetector.h"
#include "MeshCollisionDetector.h"
#include <Eris/Entity.h>
#include <Eris/View.h>
#include <Eris/TypeInfo.h>
namespace EmberOgre {
60 const char * const EmberPhysicalEntity::ACTION_STAND = "__movement_idle";
61 const char * const EmberPhysicalEntity::ACTION_RUN = "__movement_run";
62 const char * const EmberPhysicalEntity::ACTION_WALK = "__movement_walk";
63 const char * const EmberPhysicalEntity::ACTION_SWIM = "__movement_swim";
64 const char * const EmberPhysicalEntity::ACTION_FLOAT = "__movement_float";
68 EmberPhysicalEntity::EmberPhysicalEntity( const std::string& id, Eris::TypeInfo* ty, Eris::View* vw, Ogre::SceneManager* sceneManager ) :
EmberEntity( id, ty, vw, sceneManager ),
mCurrentMovementAction( 0 ),
mActiveAction( 0 ),
mModelAttachedTo( 0 ),
mModelMarkedToAttachTo( 0 ),
mModel( 0 ),
mScaleNode( 0 ),
mModelMapping( 0 )
{
}
80 EmberPhysicalEntity::~EmberPhysicalEntity( )
{
delete mModelMapping;
if ( mModel ) {
delete mModel->getUserObject( );
getSceneManager( )->destroyMovableObject( mModel );
}
Ogre::SceneNode *parent = static_cast<Ogre::SceneNode*>( getScaleNode( )->getParent( ) );
if ( parent ) {
parent->removeAndDestroyChild( getScaleNode( )->getName( ) );
}
///make sure it's not in the MotionManager
///TODO: keep a marker in the entity so we don't need to call this for all entities
MotionManager::getSingleton( ).removeAnimatedEntity( this );
/*
mSceneManager->removeEntity( mOgreEntity );
mSceneManager->removeEntity( mOgreEntity );
delete mOgreEntity;
delete mSceneNode;
*/
}
107 EmberEntity* EmberPhysicalEntity::getEntityAttachedToPoint( const std::string& attachPoint )
{
///first check with the attach points
const std::string* entityId( 0 );
for( AttachedEntitiesStore::const_iterator I = mAttachedEntities.begin( ); I != mAttachedEntities.end( ); ++I ) {
if ( I->second == attachPoint ) {
entityId = &I->first;
break;
}
}
if ( entityId ) {
///then get the entity from the world
EmberEntity* entity = EmberOgre::getSingleton( ).getEmberEntity( *entityId );
return entity;
}
return 0;
}
127 void EmberPhysicalEntity::setVisible( bool visible )
{
EmberEntity::setVisible( visible );
// if ( !visible ) {
// if ( getScaleNode( )->getParent( ) ) {
// mOgreNode->removeChild( getScaleNode( ) );
// }
// } else {
// if ( !getScaleNode( )->getParent( ) ) {
// mOgreNode->addChild( getScaleNode( ) );
// }
// }
getScaleNode( )->setVisible( visible && getLocation( ), false );
//getModel( )->setVisible( visible );
}
143 void EmberPhysicalEntity::createScaleNode( )
{
mScaleNode = mOgreNode->createChildSceneNode( getId( ) + "_scaleNode" );
}
148 void EmberPhysicalEntity::setModel( const std::string& modelName )
{
if ( mModel ) {
if ( mModel->getDefinition( )->getName( ) == modelName ) {
return;
} else {
getSceneManager( )->destroyMovableObject( mModel );
}
}
mModel = Model::Model::createModel( EmberOgre::getSingleton( ).getSceneManager( ), modelName, getId( ) );
///if the model definition isn't valid, use a placeholder
if ( !mModel->getDefinition( )->isValid( ) ) {
S_LOG_FAILURE( "Could not find " << modelName << ", using placeholder." );
///add a placeholder model
Model::ModelDefnPtr modelDef = mModel->getDefinition( );
modelDef->createSubModelDefinition( "placeholder.mesh" )->createPartDefinition( "main" )->setShow( true );
modelDef->setValid( true );
modelDef->reloadAllInstances( );
}
///rotate node to fit with WF space
///perhaps this is something to put in the model spec instead?
// scaleNode->rotate( Ogre::Vector3::UNIT_Y, ( Ogre::Degree )90 );
mScaleNode->attachObject( mModel );
}
176 void EmberPhysicalEntity::showModelPart( const std::string& partName )
{
Model::Model* model = getModel( );
if ( model ) {
model->showPart( partName );
///if we already have set up a collision object we must reload it
EmberEntityUserObject* userObject = static_cast<EmberEntityUserObject*>( getModel( )->getUserObject( ) );
if ( userObject && userObject->getCollisionDetector( ) ) {
userObject->getCollisionDetector( )->reload( );
}
}
}
190 void EmberPhysicalEntity::hideModelPart( const std::string& partName )
{
Model::Model* model = getModel( );
if ( model ) {
model->hidePart( partName );
///if we already have set up a collision object we must reload it
EmberEntityUserObject* userObject = static_cast<EmberEntityUserObject*>( getModel( )->getUserObject( ) );
if ( userObject && userObject->getCollisionDetector( ) ) {
userObject->getCollisionDetector( )->reload( );
}
}
}
204 void EmberPhysicalEntity::init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp )
{
///first we need to create the scale node
createScaleNode( );
/// we need a model mapping
createModelMapping( );
assert( mModelMapping );
mModelMapping->initialize( );
if ( !mModel ) {
S_LOG_WARNING( "Entity of type " << getType( )->getName( ) << " have no default model, using placeholder." );
setModel( "placeholder" );
}
///once we have that, we need which model to use and can create the model
// createModel( );
onModeChanged( EmberEntity::MM_DEFAULT );
EmberEntity::init( ge, fromCreateOp );
getModel( )->setQueryFlags( MousePicker::CM_ENTITY );
/* assert( mOgreNode );
assert( mScaleNode );*/
//if there is no bounding box, scaleNode hasn't been called, so do it here
/* if ( !hasBBox( ) ) {
scaleNode( );
}*/
//translate the scale node according to the translate defined in the model
// getScaleNode( )->translate( getModel( )->getDefinition( )->getTranslate( ) );
initFromModel( );
/* EmberEntityUserObject* userObject = new EmberEntityUserObject( this, getModel( ), 0, 0 );
getModel( )->setUserObject( userObject );*/
/** If there's an idle animation, we'll randomize the entry value for that so we don't end up with too many similiar entities with synched animations ( such as when you enter the world at origo and have 20 settlers doing the exact same motions. */
Model::Action* idleaction = mModel->getAction( ACTION_STAND );
if ( idleaction ) {
idleaction->getAnimations( ).addTime( Ogre::Math::RangeRandom( 0, 15 ) );
}
//check if we should do delayed attachment
if ( mModelMarkedToAttachTo ) {
attachToPointOnModel( mAttachPointMarkedToAttachTo, mModelMarkedToAttachTo );
mModelMarkedToAttachTo = 0;
mAttachPointMarkedToAttachTo = "";
}
//NOTE: for now, add all particle systems. we will want to add some visibility flag or something in the future
for ( Model::ParticleSystemSet::iterator I = mModel->getParticleSystems( ).begin( ); I != mModel->getParticleSystems( ).end( ); ++I )
{
getScaleNode( )->attachObject( ( *I )->getOgreParticleSystem( ) );
}
getModel( )->Reloaded.connect( sigc::mem_fun( *this, &EmberPhysicalEntity::Model_Reloaded ) );
getModel( )->Resetting.connect( sigc::mem_fun( *this, &EmberPhysicalEntity::Model_Resetting ) );
}
268 void EmberPhysicalEntity::initFromModel( )
{
///make a copy of the original bbox
mDefaultOgreBoundingBox = mModel->getBoundingBox( );
getScaleNode( )->setOrientation( Ogre::Quaternion::IDENTITY );
///rotate node to fit with WF space
///perhaps this is something to put in the model spec instead?
getScaleNode( )->rotate( Ogre::Vector3::UNIT_Y, ( Ogre::Degree )90 );
getScaleNode( )->rotate( getModel( )->getRotation( ) );
scaleNode( );
getScaleNode( )->setPosition( Ogre::Vector3::ZERO );
///translate the scale node according to the translate defined in the model
getScaleNode( )->translate( getModel( )->getDefinition( )->getTranslate( ) );
connectEntities( );
const Model::RenderingDefinition* renderingDef = mModel->getDefinition( )->getRenderingDefinition( );
if ( renderingDef && renderingDef->getScheme( ) == "forest" ) {
Environment::Forest* forest = EmberOgre::getSingleton( ).getEntityFactory( )->getWorld( )->getEnvironment( )->getForest( );
for ( Model::Model::SubModelSet::const_iterator I = mModel->getSubmodels( ).begin( ); I != mModel->getSubmodels( ).end( ); ++I ) {
// if ( ( *I )->getEntity( )->isVisible( ) ) {
( *I )->getEntity( )->setVisible( true );
forest->addTree( ( *I )->getEntity( ), getScaleNode( )->getWorldPosition( ), getScaleNode( )->getWorldOrientation( ).getYaw( ), getScaleNode( )->getScale( ).y );
// }
}
mModel->setRenderingDistance( 100 );
// getScaleNode( )->detachObject( mModel );
// getSceneNode( )->removeChild( getScaleNode( ) );
// getScaleNode( )->setVisible( false );
}
}
305 void EmberPhysicalEntity::createModelMapping( )
{
delete mModelMapping;
EmberEntityActionCreator creator( *this );
mModelMapping = ::EmberOgre::Model::Mapping::EmberModelMappingManager::getSingleton( ).getManager( ).createMapping( this, &creator );
}
312 void EmberPhysicalEntity::connectEntities( )
{
if ( getModel( ) ) {
if ( getModel( )->getUserObject( ) ) {
delete getModel( )->getUserObject( );
}
// ICollisionDetector* collisionDetector = new OpcodeCollisionDetector( getModel( ) );
ICollisionDetector* collisionDetector = new MeshCollisionDetector( getModel( ) );
EmberEntityUserObject* userObject = new EmberEntityUserObject( this, getModel( ), collisionDetector );
getModel( )->setUserObject( userObject );
}
}
326 void EmberPhysicalEntity::attachToPointOnModel( const std::string& point, Model::Model* model )
{
//if we're not initialized, delay attachment until after init
if ( !isInitialized( ) ) {
mModelMarkedToAttachTo = model;
mAttachPointMarkedToAttachTo = point;
} else {
if ( model->hasAttachPoint( point ) && model->getSkeleton( ) ) {
getScaleNode( )->detachObject( getModel( ) );
getModel( )->setVisible( true );
model->attachObjectToAttachPoint( point, getModel( ), getScaleNode( )->getScale( ), getModel( )->getDefinition( )->getRotation( ) );
mModelAttachedTo = model;
}
}
}
342 void EmberPhysicalEntity::detachFromModel( )
{
if ( mModelAttachedTo ) {
mModelAttachedTo->detachObjectFromBone( getModel( )->getName( ) );
getScaleNode( )->attachObject( getModel( ) );
checkVisibility( isVisible( ) );
mModelAttachedTo = 0;
}
}
352 void EmberPhysicalEntity::showOgreBoundingBox( bool show )
{
getScaleNode( )->showBoundingBox( show );
}
358 bool EmberPhysicalEntity::getShowOgreBoundingBox( ) const
{
return getScaleNode( )->getShowBoundingBox( );
}
363 Model::Model* EmberPhysicalEntity::getModel( ) const
{
return mModel;
}
368 void EmberPhysicalEntity::Model_Reloaded( )
{
initFromModel( );
attachAllEntities( );
}
374 void EmberPhysicalEntity::Model_Resetting( )
{
if ( getModel( )->getUserObject( ) ) {
delete getModel( )->getUserObject( );
}
getModel( )->setUserObject( 0 );
detachAllEntities( );
}
383 void EmberPhysicalEntity::processWield( const std::string& wieldName, const Atlas::Message::Element& idElement )
{
S_LOG_VERBOSE( "Set " << wieldName << " to " << idElement.asString( ) );
const std::string& id = idElement.asString( );
if ( id.empty( ) ) {
detachEntity( wieldName );
} else {
//detach first
detachEntity( wieldName );
attachEntity( wieldName, id );
}
}
396 void EmberPhysicalEntity::processOutfit( const Atlas::Message::MapType & outfitMap )
{
}
401 void EmberPhysicalEntity::onAttrChanged( const std::string& str, const Atlas::Message::Element& v ) {
EmberEntity::onAttrChanged( str, v );
///this is kind of a hack, but it allows characters to wield other entities in their hands
if ( str == "right_hand_wield" || str == "left_hand_wield" ) {
processWield( str, v );
return;
}
// if ( str == "outfit" ) {
// if ( v.isMap( ) ) {
// const Atlas::Message::MapType & outfitMap = v.asMap( );
// int i = 0;
// }
// }
// if ( str == "bbox" ) {
// scaleNode( );
// }
//check if the changed attribute should affect any particle systems
if ( mModel->hasParticles( ) ) {
const Model::ParticleSystemBindingsPtrSet& bindings = mModel->getAllParticleSystemBindings( );
for ( Model::ParticleSystemBindingsPtrSet::const_iterator I = bindings.begin( ); I != bindings.end( ); ++I ) {
if ( ( *I )->getVariableName( ) == str && v.isNum( ) ) {
( *I )->scaleValue( v.asNum( ) );
}
}
}
}
432 void EmberPhysicalEntity::onModeChanged( MovementMode newMode )
{
/* if ( newMode != mMovementMode )
{*/
const char * actionName;
if ( newMode == EmberEntity::MM_WALKING ) {
actionName = ACTION_WALK;
} else if ( newMode == EmberEntity::MM_RUNNING ) {
actionName = ACTION_RUN;
} else if ( newMode == EmberEntity::MM_SWIMMING ) {
actionName = ACTION_SWIM;
} else {
actionName = ACTION_STAND;
}
if ( !mCurrentMovementAction || mCurrentMovementAction->getName( ) != actionName ) {
///first disable the current action
if ( mCurrentMovementAction ) {
mCurrentMovementAction->getAnimations( ).reset( );
}
Model::Action* newAction = mModel->getAction( actionName );
mCurrentMovementAction = newAction;
if ( newAction ) {
MotionManager::getSingleton( ).addAnimatedEntity( this );
// mCurrentMovementAction->getAnimations( )->setEnabled( true );
} else {
MotionManager::getSingleton( ).removeAnimatedEntity( this );
}
}
//might set mCurrentMovementAction to 0
// }
EmberEntity::onModeChanged( newMode );
}
469 void EmberPhysicalEntity::onChildAdded( Entity *e )
{
Eris::Entity::onChildAdded( e );
//see if it's in our attach map
if ( mAttachedEntities.find( e->getId( ) ) != mAttachedEntities.end( ) ) {
EmberEntity* emberEntity = static_cast<EmberEntity*>( e );
emberEntity->attachToPointOnModel( mAttachedEntities[e->getId( )], getModel( ) );
}
/* if ( hasChild( entityId ) ) {
}*/
}
486 void EmberPhysicalEntity::onChildRemoved( Entity *e )
{
//NOTE: we don't have to do detachment here, like we do attachment in onChildAdded, since that is done by the EmberEntity::onLocationChanged( ... ) method
Eris::Entity::onChildRemoved( e );
}
493 void EmberPhysicalEntity::scaleNode( ) {
getScaleNode( )->setScale( 1, 1, 1 );
const Ogre::Vector3& ogreMax = mDefaultOgreBoundingBox.getMaximum( );
const Ogre::Vector3& ogreMin = mDefaultOgreBoundingBox.getMinimum( );
if ( hasBBox( ) ) {
const WFMath::AxisBox<3>& wfBoundingBox = getBBox( );
const WFMath::Point<3>& wfMax = wfBoundingBox.highCorner( );
const WFMath::Point<3>& wfMin = wfBoundingBox.lowCorner( );
Ogre::Real scaleX;
Ogre::Real scaleY;
Ogre::Real scaleZ;
switch ( getModel( )->getUseScaleOf( ) ) {
case Model::ModelDefinition::MODEL_HEIGHT:
scaleX = scaleY = scaleZ = fabs( ( wfMax.z( ) - wfMin.z( ) ) / ( ogreMax.y - ogreMin.y ) );
break;
case Model::ModelDefinition::MODEL_WIDTH:
scaleX = scaleY = scaleZ = fabs( ( wfMax.x( ) - wfMin.x( ) ) / ( ogreMax.x - ogreMin.x ) );
break;
case Model::ModelDefinition::MODEL_DEPTH:
scaleX = scaleY = scaleZ = fabs( ( wfMax.y( ) - wfMin.y( ) ) / ( ogreMax.z - ogreMin.z ) );
break;
case Model::ModelDefinition::MODEL_NONE:
scaleX = scaleY = scaleZ = 1;
break;
case Model::ModelDefinition::MODEL_ALL:
default:
scaleX = fabs( ( wfMax.x( ) - wfMin.x( ) ) / ( ogreMax.x - ogreMin.x ) );
scaleY = fabs( ( wfMax.z( ) - wfMin.z( ) ) / ( ogreMax.y - ogreMin.y ) );
scaleZ = fabs( ( wfMax.y( ) - wfMin.y( ) ) / ( ogreMax.z - ogreMin.z ) );
}
//Ogre::Real finalScale = std::max( scaleX, scaleY );
//finalScale = std::max( finalScale, scaleZ );
getScaleNode( )->setScale( scaleX, scaleY, scaleZ );
} else if ( !getModel( )->getScale( ) ) {
//set to small size
Ogre::Real scaleX = ( 0.25 / ( ogreMax.x - ogreMin.x ) );
Ogre::Real scaleY = ( 0.25 / ( ogreMax.y - ogreMin.y ) );
Ogre::Real scaleZ = ( 0.25 / ( ogreMax.z - ogreMin.z ) );
getScaleNode( )->setScale( scaleX, scaleY, scaleZ );
}
if ( getModel( )->getScale( ) ) {
if ( getModel( )->getScale( ) != 1 ) {
//only scale if it's not 1
getScaleNode( )->scale( getModel( )->getScale( ), getModel( )->getScale( ), getModel( )->getScale( ) );
}
}
}
557 const Ogre::Vector3& EmberPhysicalEntity::getOffsetForContainedNode( const Ogre::Vector3& position, EmberEntity* const entity )
{
///if the model has an offset specified, use that, else just send to the base class
const Ogre::Vector3& offset = getModel( )->getDefinition( )->getContentOffset( );
if ( offset != Ogre::Vector3::ZERO ) {
return offset;
} else {
return EmberEntity::getOffsetForContainedNode( position, entity );
}
}
570 void EmberPhysicalEntity::updateMotion( Ogre::Real timeSlice )
{
EmberEntity::updateMotion( timeSlice );
}
576 void EmberPhysicalEntity::updateAnimation( Ogre::Real timeSlice )
{
if ( mActiveAction ) {
bool continuePlay = false;
mActiveAction->getAnimations( ).addTime( timeSlice, continuePlay );
if ( !continuePlay ) {
mActiveAction->getAnimations( ).reset( );
mActiveAction = 0;
}
} else {
if ( mCurrentMovementAction ) {
bool continuePlay = false;
//check if we're walking backward
if ( static_cast<int>( ( WFMath::Vector<3>( getVelocity( ) ).rotate( ( getOrientation( ).inverse( ) ) ) ).x( ) ) < 0 ) {
mCurrentMovementAction->getAnimations( ).addTime( -timeSlice, continuePlay );
} else {
mCurrentMovementAction->getAnimations( ).addTime( timeSlice, continuePlay );
}
}
}
}
598 void EmberPhysicalEntity::setMoving( bool moving )
{
// MotionManager* motionManager = &MotionManager::getSingleton( );
// if ( moving ) {
// if ( getModel( )->isAnimated( ) ) {
// getModel( )->stopAnimation( "idle" );
// getModel( )->startAnimation( "walk" );
// }
// } else {
// if ( getModel( )->isAnimated( ) ) {
// getModel( )->stopAnimation( "walk" );
// getModel( )->startAnimation( "idle" );
// }
// }
EmberEntity::setMoving( moving );
}
615 void EmberPhysicalEntity::detachEntity( const std::string & attachPoint )
{
const std::string* entityId( 0 );
for( AttachedEntitiesStore::const_iterator I = mAttachedEntities.begin( ); I != mAttachedEntities.end( ); ++I ) {
if ( I->second == attachPoint ) {
entityId = &I->first;
break;
}
}
if ( entityId ) {
if ( hasChild( *entityId ) ) {
//we already have the entity, do the detachment
EmberEntity* entity = EmberOgre::getSingleton( ).getEntity( *entityId );
if ( entity ) {
entity->detachFromModel( );
}
}
mAttachedEntities.erase( *entityId );
}
}
637 void EmberPhysicalEntity::attachEntity( const std::string & attachPoint, const std::string & entityId )
{
mAttachedEntities[entityId] = attachPoint;
if ( hasChild( entityId ) ) {
//we already have the entity, do the attachment now, else we will just wait for the onChildAdded event
EmberEntity* entity = EmberOgre::getSingleton( ).getEntity( entityId );
if ( entity ) {
entity->attachToPointOnModel( attachPoint, getModel( ) );
}
}
}
649 void EmberPhysicalEntity::detachAllEntities( )
{
for( AttachedEntitiesStore::const_iterator I = mAttachedEntities.begin( ); I != mAttachedEntities.end( ); ++I ) {
detachEntity( I->first );
}
}
656 void EmberPhysicalEntity::attachAllEntities( )
{
//HACK: this should be data driven
if ( hasAttr( "right_hand_wield" ) ) {
const Atlas::Message::Element& idElement = valueOfAttr( "right_hand_wield" );
attachEntity( "right_hand_wield", idElement.asString( ) );
} else if ( hasAttr( "left_hand_wield" ) ) {
const Atlas::Message::Element& idElement = valueOfAttr( "left_hand_wield" );
attachEntity( "left_hand_wield", idElement.asString( ) );
}
}
669 void EmberPhysicalEntity::onBboxChanged( )
{
EmberEntity::onBboxChanged( );
scaleNode( );
}
675 const Ogre::AxisAlignedBox& EmberPhysicalEntity::getWorldBoundingBox( bool derive ) const
{
return getModel( )->getWorldBoundingBox( derive );
}
680 const Ogre::Sphere & EmberPhysicalEntity::getWorldBoundingSphere ( bool derive ) const
{
return getModel( )->getWorldBoundingSphere( derive );
}
685 void EmberPhysicalEntity::onAction( const Atlas::Objects::Operation::RootOperation& act )
{
/* std::string allattribs;
//Atlas::Objects::BaseObjectData::const_iterator I = act->begin( );
std::list< std::string >::const_iterator I = act->getParents( ).begin( );
for ( ; I != act->getParents( ).end( ); ++I )
{
//const Atlas::Message::Element e = ( const Atlas::Message::Element )( *I ).second;
allattribs.append( ( *I ) + " : " );
}*/
const std::list<std::string> &p = act->getParents( );
std::list<std::string>::const_iterator I = p.begin( );
if ( I != p.end( ) ) {
const std::string& name = *I;
Model::Action* newAction = mModel->getAction( name );
///If there's no action found, try to see if we have a "default action" defined to play instead.
if ( !newAction ) {
newAction = mModel->getAction( "default_action" );
}
if ( newAction ) {
MotionManager::getSingleton( ).addAnimatedEntity( this );
mActiveAction = newAction;
newAction->getAnimations( ).reset( );
mCurrentMovementAction->getAnimations( ).reset( );
}
}
EmberEntity::onAction( act );
}
723 bool EmberPhysicalEntity::allowVisibilityOfMember( EmberEntity* entity ) {
return mModel->getDefinition( )->getShowContained( );
}
727 void EmberPhysicalEntity::setVisualize( const std::string& visualization, bool visualize )
{
if ( visualization == "CollisionObject" ) {
if ( getModel( ) ) {
EmberEntityUserObject* userObject = static_cast<EmberEntityUserObject*>( getModel( )->getUserObject( ) );
if ( userObject && userObject->getCollisionDetector( ) ) {
userObject->getCollisionDetector( )->setVisualize( visualize );
}
}
} else {
EmberEntity::setVisualize( visualization, visualize );
}
}
741 bool EmberPhysicalEntity::getVisualize( const std::string& visualization ) const
{
if ( visualization == "CollisionObject" ) {
if ( getModel( ) ) {
EmberEntityUserObject* userObject = static_cast<EmberEntityUserObject*>( getModel( )->getUserObject( ) );
if ( userObject && userObject->getCollisionDetector( ) ) {
return userObject->getCollisionDetector( )->getVisualize( );
}
}
return false;
} else {
return EmberEntity::getVisualize( visualization );
}
}
/*
void EmberPhysicalEntity::handleTalk( const std::string &msg )
{
std::string message = "<";
message.append( getName( ) );
message.append( "> " );
message.append( msg );
std::cout << "TRACE - ENTITY SAYS: [" << message << "]\n" << std::endl;
Ember::ConsoleBackend::getMainConsole( )->pushMessage( message );
}
*/
/*
void EmberPhysicalEntity::setContainer( Entity *pr )
{
EmberEntity* EmberEntity = dynamic_cast<EmberEntity*>( pr );
if ( EmberEntity ) {
//detach from our current object and add to the new entity
getSceneNode( )->getParent( )->removeChild( getSceneNode( )->getName( ) );
EmberEntity->getSceneNode( )->addChild( getSceneNode( ) );
} else {
//detach from our current object and add to the world
getSceneNode( )->getParent( )->removeChild( getSceneNode( )->getName( ) );
getSceneNode( )->getCreator( )->getRootSceneNode( )->addChild( getSceneNode( ) );
}
}
*/
}
/*
Copyright ( C ) 2004 Erik Hjortsberg
some parts Copyright ( C ) 2004 bad_camel at Ogre3d forums
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DIMEPHYSICALENTITY_H
#define DIMEPHYSICALENTITY_H
#include "EmberOgrePrerequisites.h"
#include "EmberEntity.h"
namespace EmberOgre {
namespace Model {
31 class Model;
32 class Action;
namespace Mapping {
34 class ModelMapping;
}
};
40 class EmberEntity;
typedef std::list<Model::Action*> ActionStore;
/**
* Represents a Ember entity with a physical representation in the world.
* This is represented by a an Ogre::Entity.
*/
48 class EmberPhysicalEntity : public EmberEntity
{
50 friend class EmberEntityModelAction;
51 friend class EmberEntityPartAction;
public:
static const char * const ACTION_STAND;
55 static const char * const ACTION_RUN;
56 static const char * const ACTION_WALK;
57 static const char * const ACTION_SWIM;
58 static const char * const ACTION_FLOAT;
EmberPhysicalEntity( const std::string& id, Eris::TypeInfo* ty, Eris::View* vw, Ogre::SceneManager* sceneManager );
virtual ~EmberPhysicalEntity( );
/**
* return the Model of this object
*/
Model::Model* getModel( ) const;
inline Ogre::SceneNode* getScaleNode( ) const;
virtual void setVisible( bool visible );
virtual void attachToPointOnModel( const std::string& point, Model::Model* model );
virtual void detachFromModel( );
virtual void updateMotion( Ogre::Real timeSlice );
void updateAnimation( Ogre::Real timeSlice );
virtual void showOgreBoundingBox( bool show );
// virtual void showErisBoundingBox( bool show );
virtual bool getShowOgreBoundingBox( ) const;
// virtual bool getShowErisBoundingBox( );
/**
* Returns the entity that's attched to the specified point, if there is such
* @param attachPoint
* @return a pointer to the EmberEntity, or 0 if none found
*/
EmberEntity* getEntityAttachedToPoint( const std::string& attachPoint );
virtual const Ogre::AxisAlignedBox& getWorldBoundingBox( bool derive = true ) const;
virtual const Ogre::Sphere & getWorldBoundingSphere ( bool derive=true ) const;
/**
* Called by a contained member to see if the member is allowed to be shown.
* This can be reimplemented in a subclass such as AvatarEmberEntity to
* disallow things that belongs to a characters inventory to be shown.
*/
virtual bool allowVisibilityOfMember( EmberEntity* entity );
/**
* General method for turning on and off debug visualizations. Subclasses might support more types of visualizations than the ones defined here.
* @param visualization The type of visualization. Currently supports "OgreBBox" and "ErisBBox".
* @param visualize Whether to visualize or not.
*/
virtual void setVisualize( const std::string& visualization, bool visualize );
/**
* Gets whether a certain visualization is turned on or off.
* @param visualization The type of visualization. Currently supports "OgreBBox" and "ErisBBox".
* @return true if visualization is turned on, else false
*/
virtual bool getVisualize( const std::string& visualization ) const;
protected:
void setModel( const std::string& modelName );
void showModelPart( const std::string& partName );
void hideModelPart( const std::string& partName );
virtual const Ogre::Vector3& getOffsetForContainedNode( const Ogre::Vector3& position, EmberEntity* const entity );
/**
* creates EmberEntityUserObjects, connects them and sets up the collision detection system
* @return
*/
void connectEntities( );
void createModelMapping( );
void createScaleNode( );
/**
* Called when the bounding box has changed.
*/
virtual void onBboxChanged( );
/**
* Called when the movement mode has changed. We might want to update the animation of the entity, for example if it's a human.
* @param newMode
*/
virtual void onModeChanged( MovementMode newMode );
/**
The current movement action of the entity, for example a walk action or a run action.
*/
Model::Action* mCurrentMovementAction;
/**
All the active actions, except the movement action ( since it's stored in mCurrentMovementAction ).
These actions will be updated each frame.
NOTE: we currently don't allow for multiple actions playing at the same time
*/
//ActionStore mActiveActions;
Model::Action* mActiveAction;
/**
If the entity is attached to another entity, this is the model to which it is attached to.
This will be 0 if the entity isn't attached.
*/
Model::Model* mModelAttachedTo;
Model::Model* mModelMarkedToAttachTo;
std::string mAttachPointMarkedToAttachTo;
virtual void onChildAdded( Entity *e );
virtual void onChildRemoved( Entity *e );
/**
* Detaches an entity which is already wielded.
* @param entityId
*/
void detachEntity( const std::string & entityId );
/**
* Attaches an entity to a certain attach point
* @param attachPoint the name of the attachpoint to attach to
* @param entityId the id of the entity to attach to
*/
void attachEntity( const std::string & attachPoint, const std::string & entityId );
/**
Detaches all currently attached entities. Call this before the Model is resetted.
*/
void detachAllEntities( );
/**
Attaches all entities that aren't currently attached.
*/
void attachAllEntities( );
/**
* Process wield ops, which means wielding and unwielding entities. This methos will in turn call the appropriate attachEntity and detachEntity methods.
* @param wieldName the attachpoint to update
* @param idElement the id of the entity to wield
*/
void processWield( const std::string& wieldName, const Atlas::Message::Element& idElement );
/**
* Processes the outfit map and updates the appearance.
* @param outfitMap
*/
void processOutfit( const Atlas::Message::MapType & outfitMap );
/**
* Overridden from Eris::Entity
* @param str
* @param v
*/
virtual void onAttrChanged( const std::string& str, const Atlas::Message::Element& v );
/**
* Overridden from Eris::Entity
* @param act
*/
virtual void onAction( const Atlas::Objects::Operation::RootOperation& act );
typedef std::map<std::string, std::string> AttachedEntitiesStore;
/**
A store of all attached entities, indexed by their id.
*/
AttachedEntitiesStore mAttachedEntities;
// virtual void onMoved( );
/**
* Overridden from Eris::Entity
* @param moving
*/
virtual void setMoving( bool moving );
/**
* Overridden from Eris::Entity
* @param ge
*/
virtual void init( const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp );
/**
The default size of the ogre bounding box, before any scaling is done.
*/
Ogre::AxisAlignedBox mDefaultOgreBoundingBox;
/**
* Scales the Ogre::SceneNode to the size of the AxisBox defined by Eris::Entity
*/
virtual void scaleNode( );
//void setNodes( );
/**
* The model of the entity
*/
Model::Model* mModel;
/**
* We need to scale the Ogre::Entity, because the underlying media is not
* always correctly scaled.
* But since each Eris::Entity can contain child entites, we'll get problems
* with scaling if we attach the children to a scaled node.
* Thus we use a separate, scaled node.
*/
Ogre::SceneNode* mScaleNode;
void Model_Reloaded( );
void Model_Resetting( );
void initFromModel( );
Model::Mapping::ModelMapping* mModelMapping;
};
Ogre::SceneNode* EmberPhysicalEntity::getScaleNode( ) const
{
return mScaleNode;
}
}
#endif // DIMEPHYSICALENTITY_H
//
// C++ Implementation: EntityWorldPickListener
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2006
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "EntityWorldPickListener.h"
#include "EmberOgre.h"
#include "EmberEntityUserObject.h"
#include "model/Model.h"
#include "EmberEntityFactory.h"
#include "EmberEntity.h"
#include "WorldEmberEntity.h"
#include "MousePicker.h"
namespace EmberOgre {
37 EntityWorldPickListenerVisualizer::EntityWorldPickListenerVisualizer( EntityWorldPickListener& pickListener )
: mEntity( 0 ), mDebugNode( 0 )
{
mDebugNode = EmberOgre::getSingleton( ).getSceneManager( )->getRootSceneNode( )->createChildSceneNode( );
Ogre::Entity* mEntity = EmberOgre::getSingleton( ).getSceneManager( )->createEntity( "pickerDebugObject", "fireball.mesh" );
///start out with a normal material
mEntity->setMaterialName( "BasePointMarkerMaterial" );
mEntity->setRenderingDistance( 300 );
mEntity->setQueryFlags( MousePicker::CM_NONPICKABLE );
mDebugNode->attachObject( mEntity );
pickListener.EventPickedEntity.connect( sigc::mem_fun( *this, &EntityWorldPickListenerVisualizer::picker_EventPickedEntity ) );
}
51 EntityWorldPickListenerVisualizer::~EntityWorldPickListenerVisualizer( )
{
EmberOgre::getSingleton( ).getSceneManager( )->destroyEntity( mEntity );
EmberOgre::getSingleton( ).getSceneManager( )->destroySceneNode( mDebugNode->getName( ) );
}
57 void EntityWorldPickListenerVisualizer::picker_EventPickedEntity( const EntityPickResult& result, const MousePickerArgs& mouseArgs )
{
mDebugNode->setPosition( result.position );
}
64 EntityWorldPickListener::EntityWorldPickListener( )
: VisualizePicking( "visualize_picking", this, "Visualize mouse pickings." )
66 , mClosestPickingDistance( 0 )
, mFurthestPickingDistance( 0 )
, mVisualizer( 0 )
{
}
73 EntityWorldPickListener::~EntityWorldPickListener( )
{
}
77 void EntityWorldPickListener::initializePickingContext( )
{
mClosestPickingDistance = 0;
mFurthestPickingDistance = 0;
mResult = EntityPickResult( );
mResult.entity = 0;
mResult.position = Ogre::Vector3::ZERO;
mResult.distance = 0;
}
87 void EntityWorldPickListener::endPickingContext( const MousePickerArgs& mousePickerArgs )
{
if ( mResult.entity ) {
std::stringstream ss;
ss << mResult.position;
S_LOG_VERBOSE( "Picked entity: " << ss.str( ) << " distance: " << mResult.distance );
EventPickedEntity( mResult, mousePickerArgs );
}
}
100 void EntityWorldPickListener::processPickResult( bool& continuePicking, Ogre::RaySceneQueryResultEntry& entry, Ogre::Ray& cameraRay, const MousePickerArgs& mousePickerArgs )
{
if ( entry.worldFragment ) {
///this is terrain
///a position of -1, -1, -1 is not valid terrain
Ogre::SceneQuery::WorldFragment* wf = entry.worldFragment;
static Ogre::Vector3 invalidPos( -1, -1, -1 );
if ( wf->singleIntersection != invalidPos ) {
if ( mFurthestPickingDistance == 0 ) {
mResult.entity = EmberOgre::getSingleton( ).getEntityFactory( )->getWorld( );
mResult.position = wf->singleIntersection;
mResult.distance = entry.distance;
continuePicking = false;
} else {
if ( entry.distance < mResult.distance ) {
mResult.entity = EmberOgre::getSingleton( ).getEntityFactory( )->getWorld( );
mResult.position = wf->singleIntersection;
mResult.distance = entry.distance;
continuePicking = false;
}
}
}
/* std::stringstream ss;
ss << wf->singleIntersection;
S_LOG_VERBOSE( "Picked in terrain: " << ss.str( ) << " distance: " << mResult.distance );*/
} else if ( entry.movable ) {
Ogre::MovableObject* pickedMovable = entry.movable;
if ( pickedMovable->isVisible( ) && pickedMovable->getUserObject( ) != 0 && pickedMovable->getUserObject( )->getTypeName( ) == "EmberEntityPickerObject" ) {
EmberEntityUserObject* anUserObject = static_cast<EmberEntityUserObject*>( pickedMovable->getUserObject( ) );
///refit the opcode mesh to adjust for changes in the mesh ( for example animations )
anUserObject->refit( );
ICollisionDetector* collisionDetector = anUserObject->getCollisionDetector( );
if ( collisionDetector ) {
CollisionResult collisionResult;
collisionResult.collided = false;
collisionDetector->testCollision( cameraRay, collisionResult );
if ( collisionResult.collided ) {
EntityPickResult result;
result.entity = anUserObject->getEmberEntity( );
result.position = collisionResult.position;
result.distance = collisionResult.distance;
if ( mFurthestPickingDistance == 0 ) {
///test all objects that fall into this distance
mFurthestPickingDistance = ( pickedMovable->getParentSceneNode( )->getWorldPosition( ) - cameraRay.getOrigin( ) ).length( ) + pickedMovable->getBoundingRadius( );
mResult = result;
} else {
if ( ( pickedMovable->getParentSceneNode( )->getWorldPosition( ) - cameraRay.getOrigin( ) ).length( ) - pickedMovable->getBoundingRadius( ) > mFurthestPickingDistance ) {
continuePicking = false;
} else {
if ( result.distance < mResult.distance ) {
mResult = result;
}
}
}
}
}
///only do opcode detection if there's a CollisionObject
// for ( EmberEntityUserObject::CollisionObjectStore::iterator I = collisionObjects->begin( ); I != collisionObjects->end( ); ++I ) {
// OgreOpcode::ICollisionShape* collisionShape = ( *I )->getShape( );
// OgreOpcode::CollisionPair pick_result;
//
// if ( collisionShape->rayCheck( OgreOpcode::COLLTYPE_QUICK, anUserObject->getModel( )->_getParentNodeFullTransform( ), cameraRay, 1000, pick_result ) ) {
// EntityPickResult result;
// result.entity = anUserObject->getEmberEntity( );
// result.position = pick_result.contact;
// result.distance = pick_result.distance;
//
// std::stringstream ss;
// ss << result.position;
// S_LOG_VERBOSE( "Picked entity: " << ss.str( ) << " distance: " << result.distance );
// EventPickedEntity( result, mousePickerArgs );
// continuePicking = false;
//
// }
// }
}
}
}
188 void EntityWorldPickListener::runCommand( const std::string &command, const std::string &args )
{
if( VisualizePicking == command ) {
if ( mVisualizer.get( ) ) {
mVisualizer.reset( );
} else {
mVisualizer = std::auto_ptr<EntityWorldPickListenerVisualizer>( new EntityWorldPickListenerVisualizer( *this ) );
}
}
}
}
1 //
// C++ Interface: EntityWorldPickListener
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2006
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREENTITYWORLDPICKLISTENER_H
#define EMBEROGREENTITYWORLDPICKLISTENER_H
#include "EmberOgrePrerequisites.h"
#include "IWorldPickListener.h"
#include <sigc++/signal.h>
#include "framework/ConsoleObject.h"
namespace EmberOgre {
35 class EmberEntity;
36 class EntityWorldPickListener;
/**
* Struct used for returning the result of a mouse pick.
*/
struct EntityPickResult
{
EmberEntity* entity;
Ogre::Vector3 position;
Ogre::Real distance;
};
/**
Visualizes the picking operation by placing a large ball at the picked position.
*/
50 class EntityWorldPickListenerVisualizer : public virtual sigc::trackable
{
public:
53 EntityWorldPickListenerVisualizer( EntityWorldPickListener& pickListener );
54 virtual ~EntityWorldPickListenerVisualizer( );
private:
57 Ogre::Entity* mEntity;
58 Ogre::SceneNode* mDebugNode;
59 void picker_EventPickedEntity( const EntityPickResult& result, const MousePickerArgs& mouseArgs );
};
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
65 class EntityWorldPickListener : public IWorldPickListener, public Ember::ConsoleObject
{
public:
68 EntityWorldPickListener( );
70 ~EntityWorldPickListener( );
72 virtual void initializePickingContext( );
74 virtual void endPickingContext( const MousePickerArgs& mousePickerArgs );
77 virtual void processPickResult( bool& continuePicking, Ogre::RaySceneQueryResultEntry& entry, Ogre::Ray& cameraRay, const MousePickerArgs& mousePickerArgs );
79 sigc::signal<void, const EntityPickResult&, const MousePickerArgs&> EventPickedEntity;
81 const Ember::ConsoleCommandWrapper VisualizePicking;
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
88 virtual void runCommand( const std::string &command, const std::string &args );
protected:
float mClosestPickingDistance, mFurthestPickingDistance;
EntityPickResult mResult;
94 std::auto_ptr<EntityWorldPickListenerVisualizer> mVisualizer;
};
}
#endif
1 //
// C++ Implementation: FreeCameraController
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "FreeCameraController.h"
namespace EmberOgre {
27 FreeCameraController::FreeCameraController( )
{
}
32 FreeCameraController::~FreeCameraController( )
{
}
};
1 //
// C++ Interface: FreeCameraController
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREFREECAMERACONTROLLER_H
#define EMBEROGREFREECAMERACONTROLLER_H
namespace EmberOgre {
/**
@author Erik Hjortsberg
This is a controller wchich allows for free flight.
*/
33 class FreeCameraController{
public:
35 FreeCameraController( );
37 ~FreeCameraController( );
};
};
#endif
1 //
// C++ Implementation: GUICEGUIAdapter
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "GUICEGUIAdapter.h"
#include <CEGUIExceptions.h>
#include <CEGUIGlobalEventSet.h>
#include <elements/CEGUIEditbox.h>
#include <elements/CEGUIMultiLineEditbox.h>
namespace EmberOgre {
32 GUICEGUIAdapter::GUICEGUIAdapter( CEGUI::System *system, CEGUI::OgreCEGUIRenderer *renderer ):
mGuiSystem( system )
, mGuiRenderer( renderer )
, mSelectedText( 0 )
{
//lookup table for sdl scancodes and CEGUI keys
mKeyMap[SDLK_BACKSPACE] = CEGUI::Key::Backspace;
mKeyMap[SDLK_TAB] = CEGUI::Key::Tab;
/* mKeyMap[SDLK_CLEAR] = CEGUI::Key::Clear;*/
mKeyMap[SDLK_RETURN] = CEGUI::Key::Return;
mKeyMap[SDLK_PAUSE] = CEGUI::Key::Pause;
mKeyMap[SDLK_ESCAPE] = CEGUI::Key::Escape;
mKeyMap[SDLK_SPACE] = CEGUI::Key::Space;
/* mKeyMap[SDLK_EXCLAIM] = CEGUI::Key::Exclaim;*/
/* mKeyMap[SDLK_QUOTEDBL] = CEGUI::Key::;
mKeyMap[SDLK_HASH] = CEGUI::Key::;
mKeyMap[SDLK_DOLLAR] = CEGUI::Key::;
mKeyMap[SDLK_AMPERSAND] = CEGUI::Key::;
mKeyMap[SDLK_QUOTE] = CEGUI::Key::;
mKeyMap[SDLK_LEFTPAREN] = CEGUI::Key::;
mKeyMap[SDLK_RIGHTPAREN] = CEGUI::Key::;
mKeyMap[SDLK_ASTERISK] = CEGUI::Key::;*/
mKeyMap[SDLK_PLUS] = CEGUI::Key::Add;
/* mKeyMap[SDLK_COMMA] = CEGUI::Key::;*/
mKeyMap[SDLK_MINUS] = CEGUI::Key::Minus;
mKeyMap[SDLK_PERIOD] = CEGUI::Key::Period;
/* mKeyMap[SDLK_SLASH] = CEGUI::Key::;*/
mKeyMap[SDLK_0] = CEGUI::Key::One;
mKeyMap[SDLK_1] = CEGUI::Key::Two;
mKeyMap[SDLK_2] = CEGUI::Key::Two;
mKeyMap[SDLK_3] = CEGUI::Key::Three;
mKeyMap[SDLK_4] = CEGUI::Key::Four;
mKeyMap[SDLK_5] = CEGUI::Key::Five;
mKeyMap[SDLK_6] = CEGUI::Key::Six;
mKeyMap[SDLK_7] = CEGUI::Key::Seven;
mKeyMap[SDLK_8] = CEGUI::Key::Eight;
mKeyMap[SDLK_9] = CEGUI::Key::Nine;
mKeyMap[SDLK_COLON] = CEGUI::Key::Colon;
mKeyMap[SDLK_SEMICOLON] = CEGUI::Key::Semicolon;
/* mKeyMap[SDLK_LESS] = CEGUI::Key::;*/
/* mKeyMap[SDLK_EQUALS] = CEGUI::Key::;
mKeyMap[SDLK_GREATER] = CEGUI::Key::;
mKeyMap[SDLK_QUESTION] = CEGUI::Key::;*/
/* mKeyMap[SDLK_AT] = CEGUI::Key::;*/
/* mKeyMap[SDLK_LEFTBRACKET] = CEGUI::Key::;*/
mKeyMap[SDLK_BACKSLASH] = CEGUI::Key::Backslash;
/* mKeyMap[SDLK_RIGHTBRACKET] = CEGUI::Key::;*/
/* mKeyMap[SDLK_CARET] = CEGUI::Key::;
mKeyMap[SDLK_UNDERSCORE] = CEGUI::Key::;
mKeyMap[SDLK_BACKQUOTE] = CEGUI::Key::;*/
mKeyMap[SDLK_a] = CEGUI::Key::A;
mKeyMap[SDLK_b] = CEGUI::Key::B;
mKeyMap[SDLK_c] = CEGUI::Key::C;
mKeyMap[SDLK_d] = CEGUI::Key::D;
mKeyMap[SDLK_e] = CEGUI::Key::E;
mKeyMap[SDLK_f] = CEGUI::Key::F;
mKeyMap[SDLK_g] = CEGUI::Key::G;
mKeyMap[SDLK_h] = CEGUI::Key::H;
mKeyMap[SDLK_i] = CEGUI::Key::I;
mKeyMap[SDLK_j] = CEGUI::Key::J;
mKeyMap[SDLK_k] = CEGUI::Key::K;
mKeyMap[SDLK_l] = CEGUI::Key::L;
mKeyMap[SDLK_m] = CEGUI::Key::M;
mKeyMap[SDLK_n] = CEGUI::Key::N;
mKeyMap[SDLK_o] = CEGUI::Key::O;
mKeyMap[SDLK_p] = CEGUI::Key::P;
mKeyMap[SDLK_q] = CEGUI::Key::Q;
mKeyMap[SDLK_r] = CEGUI::Key::R;
mKeyMap[SDLK_s] = CEGUI::Key::S;
mKeyMap[SDLK_t] = CEGUI::Key::T;
mKeyMap[SDLK_u] = CEGUI::Key::U;
mKeyMap[SDLK_v] = CEGUI::Key::V;
mKeyMap[SDLK_w] = CEGUI::Key::W;
mKeyMap[SDLK_x] = CEGUI::Key::X;
mKeyMap[SDLK_y] = CEGUI::Key::Y;
mKeyMap[SDLK_z] = CEGUI::Key::Z;
mKeyMap[SDLK_DELETE] = CEGUI::Key::Delete;
mKeyMap[SDLK_UP] = CEGUI::Key::ArrowUp;
mKeyMap[SDLK_DOWN] = CEGUI::Key::ArrowDown;
mKeyMap[SDLK_RIGHT] = CEGUI::Key::ArrowRight;
mKeyMap[SDLK_LEFT] = CEGUI::Key::ArrowLeft;
mKeyMap[SDLK_INSERT] = CEGUI::Key::Insert;
mKeyMap[SDLK_HOME] = CEGUI::Key::Home;
mKeyMap[SDLK_END] = CEGUI::Key::End;
mKeyMap[SDLK_PAGEUP] = CEGUI::Key::PageUp;
mKeyMap[SDLK_PAGEDOWN] = CEGUI::Key::PageDown;
mKeyMap[SDLK_F1] = CEGUI::Key::F1;
mKeyMap[SDLK_F2] = CEGUI::Key::F2;
mKeyMap[SDLK_F3] = CEGUI::Key::F3;
mKeyMap[SDLK_F4] = CEGUI::Key::F4;
mKeyMap[SDLK_F5] = CEGUI::Key::F5;
mKeyMap[SDLK_F6] = CEGUI::Key::F6;
mKeyMap[SDLK_F7] = CEGUI::Key::F7;
mKeyMap[SDLK_F8] = CEGUI::Key::F8;
mKeyMap[SDLK_F9] = CEGUI::Key::F9;
mKeyMap[SDLK_F10] = CEGUI::Key::F10;
mKeyMap[SDLK_F11] = CEGUI::Key::F11;
mKeyMap[SDLK_F12] = CEGUI::Key::F12;
mKeyMap[SDLK_F13] = CEGUI::Key::F13;
mKeyMap[SDLK_F14] = CEGUI::Key::F14;
mKeyMap[SDLK_F15] = CEGUI::Key::F15;
mKeyMap[SDLK_NUMLOCK] = CEGUI::Key::NumLock;
mKeyMap[SDLK_SCROLLOCK] = CEGUI::Key::ScrollLock;
mKeyMap[SDLK_RSHIFT] = CEGUI::Key::RightShift;
mKeyMap[SDLK_LSHIFT] = CEGUI::Key::LeftShift;
mKeyMap[SDLK_RCTRL] = CEGUI::Key::RightControl;
mKeyMap[SDLK_LCTRL] = CEGUI::Key::LeftControl;
mKeyMap[SDLK_RALT] = CEGUI::Key::RightAlt;
mKeyMap[SDLK_LALT] = CEGUI::Key::LeftAlt;
///set up the capturing of text selected event for the copy-and-paste functionality
//window->subscribeEvent( event, CEGUI::Event::Subscriber( &method, this ) );
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( "MultiLineEditbox/TextSelectionChanged", CEGUI::Event::Subscriber( &GUICEGUIAdapter::MultiLineEditbox_selectionChangedHandler, this ) );
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( "Editbox/TextSelectionChanged", CEGUI::Event::Subscriber( &GUICEGUIAdapter::Editbox_selectionChangedHandler, this ) );
//CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( "Editbox/TextSelectionChanged", &GUICEGUIAdapter::selectionChangedHandler );
}
157 GUICEGUIAdapter::~GUICEGUIAdapter( )
{
}
161 bool GUICEGUIAdapter::MultiLineEditbox_selectionChangedHandler( const CEGUI::EventArgs& args )
{
CEGUI::MultiLineEditbox* editbox = static_cast<CEGUI::MultiLineEditbox*>( mGuiSystem->getGUISheet( )->getActiveChild( ) );
mSelectedText = &editbox->getText( );
mSelectionStart = editbox->getSelectionStartIndex( );
mSelectionEnd = editbox->getSelectionEndIndex( );
/* const CEGUI::String& text = editbox->getText( );
if ( editbox->getSelectionLength( ) > 0 ) {
std::string selection = text.substr( editbox->getSelectionStartIndex( ), editbox->getSelectionEndIndex( ) ).c_str( );
S_LOG_VERBOSE( "Selected text: " << selection );
}*/
// S_LOG_VERBOSE( "Selected text." );
return true;
}
177 bool GUICEGUIAdapter::Editbox_selectionChangedHandler( const CEGUI::EventArgs& args )
{
CEGUI::Editbox* editbox = static_cast<CEGUI::Editbox*>( mGuiSystem->getGUISheet( )->getActiveChild( ) );
mSelectedText = &editbox->getText( );
mSelectionStart = editbox->getSelectionStartIndex( );
mSelectionEnd = editbox->getSelectionEndIndex( );
S_LOG_VERBOSE( "Selected text." );
return true;
}
// bool GUICEGUIAdapter::selectionChangedHandler( const CEGUI::EventArgs& args )
// {
// S_LOG_VERBOSE( "" );
// }
192 bool GUICEGUIAdapter::injectMouseMove( const MouseMotion& motion, bool& freezeMouse )
{
try {
CEGUI::MouseCursor::getSingleton( ).setPosition( CEGUI::Point( ( motion.xPosition ), ( motion.yPosition ) ) );
mGuiSystem->injectMouseMove( 0.0f, 0.0f );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return true;
}
203 bool GUICEGUIAdapter::injectMouseButtonUp( const Input::MouseButton& button )
{
CEGUI::MouseButton ceguiButton;
if ( button == Input::MouseButtonLeft ) {
ceguiButton = CEGUI::LeftButton;
} else if( button == Input::MouseButtonRight ) {
ceguiButton = CEGUI::RightButton;
} else if( button == Input::MouseButtonMiddle ) {
ceguiButton = CEGUI::MiddleButton;
} else {
return true;
}
try {
mGuiSystem->injectMouseButtonUp( ceguiButton );
return false;
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
} catch ( ... ) {
S_LOG_WARNING( "Unknown error in CEGUI." );
}
return true;
}
227 bool GUICEGUIAdapter::injectMouseButtonDown( const Input::MouseButton& button )
{
CEGUI::MouseButton ceguiButton;
if ( button == Input::MouseButtonLeft ) {
ceguiButton = CEGUI::LeftButton;
} else if( button == Input::MouseButtonRight ) {
ceguiButton = CEGUI::RightButton;
} else if( button == Input::MouseButtonMiddle ) {
ceguiButton = CEGUI::MiddleButton;
} else if( button == Input::MouseWheelDown ) {
try {
mGuiSystem->injectMouseWheelChange( -1.0 );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return false;
} else if( button == Input::MouseWheelUp ) {
try {
mGuiSystem->injectMouseWheelChange( 1.0 );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return false;
} else {
return true;
}
try {
mGuiSystem->injectMouseButtonDown( ceguiButton );
return false;
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return true;
}
263 bool GUICEGUIAdapter::injectChar( char character )
{
try {
//cegui can't handle tabs, so we have to convert it to a couple of spaces
if ( character == '\t' ) {
mGuiSystem->injectChar( ' ' );
mGuiSystem->injectChar( ' ' );
mGuiSystem->injectChar( ' ' );
mGuiSystem->injectChar( ' ' );
//can't handle CR either really, insert a line break ( 0x0a ) instead
} else if ( character == '\r' ) {
//mGuiSystem->injectChar( 0x0a );
mGuiSystem->injectKeyDown( CEGUI::Key::Return );
mGuiSystem->injectKeyUp( CEGUI::Key::Return );
} else {
mGuiSystem->injectChar( character );
}
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return true;
}
287 bool GUICEGUIAdapter::injectKeyDown( const SDLKey& key )
{
try {
mGuiSystem->injectKeyDown( mKeyMap[key] );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return true;
}
298 bool GUICEGUIAdapter::injectKeyUp( const SDLKey& key )
{
try {
mGuiSystem->injectKeyUp( mKeyMap[key] );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
return true;
}
}
1 //
// C++ Interface: GUICEGUIAdapter
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREGUICEGUIADAPTER_H
#define EMBEROGREGUICEGUIADAPTER_H
#include "EmberOgrePrerequisites.h"
#include <CEGUISystem.h>
#include <CEGUIEventArgs.h>
#include <CEGUIInputEvent.h>
#include "input/IInputAdapter.h"
#include "input/Input.h"
namespace CEGUI {
36 class System;
37 class OgreCEGUIRenderer;
}
namespace EmberOgre {
43 TYPEDEF_STL_MAP( SDLKey, CEGUI::Key::Scan, SDLKeyMap );
/**
@author Erik Hjortsberg
Provides an adapter between the input system and CEGUI.
*/
50 class GUICEGUIAdapter : public IInputAdapter {
public:
/**
* Creates a new instance.
* @param system A valid CEGUI::System
* @param renderer A valid CEGUI::OgreCEGUIRenderer
* @return
*/
59 GUICEGUIAdapter( CEGUI::System *system, CEGUI::OgreCEGUIRenderer *renderer );
61 ~GUICEGUIAdapter( );
63 virtual bool injectMouseMove( const MouseMotion& motion, bool& freezeMouse );
64 virtual bool injectMouseButtonUp( const Input::MouseButton& button );
65 virtual bool injectMouseButtonDown( const Input::MouseButton& button );
66 virtual bool injectChar( char character );
67 virtual bool injectKeyDown( const SDLKey& key );
68 virtual bool injectKeyUp( const SDLKey& key );
private:
71 CEGUI::System *mGuiSystem;
72 CEGUI::OgreCEGUIRenderer *mGuiRenderer;
/**
mapping of SDL-keys to CEGUI keys
*/
77 SDLKeyMap mKeyMap;
79 bool MultiLineEditbox_selectionChangedHandler( const CEGUI::EventArgs& args );
80 bool Editbox_selectionChangedHandler( const CEGUI::EventArgs& args );
82 const CEGUI::String* mSelectedText;
83 size_t mSelectionStart, mSelectionEnd;
};
}
#endif
/*
Copyright ( C ) 2004 Miguel Guzman ( Aganor )
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "GUIManager.h"
#include "services/EmberServices.h"
#include "services/config/ConfigService.h"
#include "services/scripting/ScriptingService.h"
#include <CEGUIWindowManager.h>
#include <CEGUISchemeManager.h>
#include <CEGUIExceptions.h>
#include <CEGUIFactoryModule.h>
#include <elements/CEGUIPushButton.h>
#include <elements/CEGUIGUISheet.h>
#include <elements/CEGUIMultiLineEditbox.h>
#include <elements/CEGUIEditbox.h>
#include "widgets/Widget.h"
#include "MousePicker.h"
#include "AvatarCamera.h"
#include "EmberOgre.h"
#include "input/Input.h"
#include "gui/ActiveWidgetHandler.h"
#include "widgets/WidgetDefinitions.h"
#include "EmberEntity.h"
#include "EmberPhysicalEntity.h"
#include "AvatarEmberEntity.h"
#include "framework/IScriptingProvider.h"
#include "components/ogre/scripting/LuaScriptingProvider.h"
#include "GUICEGUIAdapter.h"
#include "widgets/icons/IconManager.h"
#include "widgets/EntityIconManager.h"
#ifdef __WIN32__
#include <windows.h>
#include <direct.h>
#endif
#include "EntityWorldPickListener.h"
template<> EmberOgre::GUIManager* Ember::Singleton<EmberOgre::GUIManager>::ms_Singleton = 0;
using namespace CEGUI;
using namespace EmberOgre::Gui;
namespace EmberOgre {
72 unsigned long GUIManager::msAutoGenId( 0 );
75 GUIManager::GUIManager( Ogre::RenderWindow* window, Ogre::SceneManager* sceneMgr )
: ToggleInputMode( "toggle_inputmode", this, "Toggle the input mode." )
77 , ReloadGui( "reloadgui", this, "Reloads the gui." )
, mGuiCommandMapper( "gui", "key_bindings_gui" )
, mPicker( 0 )
, mEntityWorldPickListener( 0 )
, mSheet( 0 )
, mWindowManager( 0 )
, mDebugText( 0 )
, mWindow( window )
, mGuiSystem( 0 )
, mGuiRenderer( 0 )
, mLuaScriptModule( 0 )
, mIconManager( 0 )
, mActiveWidgetHandler( 0 )
{
mGuiCommandMapper.restrictToInputMode( Input::IM_GUI );
///we need this here just to force the linker to also link in the WidgetDefinitions
WidgetDefinitions w;
try {
S_LOG_INFO( "Starting CEGUI" );
mDefaultScheme = "EmberLook";
S_LOG_VERBOSE( "Setting default scheme to "<< mDefaultScheme );
Ember::ConfigService* configSrv = Ember::EmberServices::getSingletonPtr( )->getConfigService( );
if ( chdir( configSrv->getEmberDataDirectory( ).c_str( ) ) ) {
S_LOG_WARNING( "Failed to change to the data directory. Gui loading might fail." );
}
//use a macro from CEGUIFactoryModule
//DYNLIB_LOAD( "libCEGUIFalagardBase.so" );
mGuiRenderer = new CEGUI::OgreCEGUIRenderer( window, Ogre::RENDER_QUEUE_OVERLAY, false, 0, sceneMgr );
// mScriptManager = new GUIScriptManager( );
CEGUI::ResourceProvider* resourceProvider = mGuiRenderer->createResourceProvider( );
resourceProvider->setDefaultResourceGroup( "Gui" );
Ember::IScriptingProvider* provider;
provider = Ember::EmberServices::getSingleton( ).getScriptingService( )->getProviderFor( "LuaScriptingProvider" );
if ( provider != 0 ) {
LuaScriptingProvider* luaScriptProvider = static_cast<LuaScriptingProvider*>( provider );
mLuaScriptModule = new LuaScriptModule( luaScriptProvider->getLuaState( ) );
mGuiSystem = new CEGUI::System( mGuiRenderer, resourceProvider, 0, mLuaScriptModule, "cegui/datafiles/configs/cegui.config" );
Ember::EmberServices::getSingleton( ).getScriptingService( )->EventStopping.connect( sigc::mem_fun( *this, &GUIManager::scriptingServiceStopping ) );
} else {
mGuiSystem = new CEGUI::System( mGuiRenderer, resourceProvider, 0, 0, "cegui/datafiles/configs/cegui.config" );
}
mWindowManager = &CEGUI::WindowManager::getSingleton( );
try {
mGuiSystem->setDefaultMouseCursor( getDefaultScheme( ), "MouseArrow" );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_FAILURE( "CEGUI - could not set mouse pointer. Make sure that the correct scheme " << getDefaultScheme( ) << " is available. Message: " << ex.getMessage( ).c_str( ) );
throw Ember::Exception( ex.getMessage( ).c_str( ) );
}
mSheet = mWindowManager->createWindow( ( CEGUI::utf8* )"DefaultGUISheet", ( CEGUI::utf8* )"root_wnd" );
mGuiSystem->setGUISheet( mSheet );
mSheet->activate( );
mSheet->moveToBack( );
mSheet->setDistributesCapturedInputs( false );
BIND_CEGUI_EVENT( mSheet, CEGUI::ButtonBase::EventMouseButtonDown, GUIManager::mSheet_MouseButtonDown );
BIND_CEGUI_EVENT( mSheet, CEGUI::Window::EventInputCaptureLost, GUIManager::mSheet_CaptureLost );
BIND_CEGUI_EVENT( mSheet, CEGUI::ButtonBase::EventMouseDoubleClick, GUIManager::mSheet_MouseDoubleClick );
//set a default tool tip
CEGUI::System::getSingleton( ).setDefaultTooltip( getDefaultScheme( ) + "/Tooltip" );
S_LOG_INFO( "CEGUI system set up" );
mPicker = new MousePicker( );
///create a new entity world pick listener which listens for event
///TODO: should this really be here?
mEntityWorldPickListener = new EntityWorldPickListener( );
///don't connect it yet since there's no AvatarCamera yet, wait until that's created
EmberOgre::getSingleton( ).EventAvatarControllerCreated.connect( sigc::mem_fun( *this, &GUIManager::EmberOgre_AvatarControllerCreated ) );
getInput( ).EventKeyPressed.connect( sigc::mem_fun( *this, &GUIManager::pressedKey ) );
getInput( ).setInputMode( Input::IM_GUI );
///add adapter for CEGUI
mCEGUIAdapter = new GUICEGUIAdapter( mGuiSystem, mGuiRenderer );
getInput( ).addAdapter( mCEGUIAdapter );
mGuiCommandMapper.bindToInput( getInput( ) );
///connect to the creation of the avatar, since we want to switch to movement mode when that happens
EmberOgre::getSingleton( ).EventCreatedAvatarEntity.connect( sigc::mem_fun( *this, &GUIManager::EmberOgre_CreatedAvatarEntity ) );
mActiveWidgetHandler = new Gui::ActiveWidgetHandler( *this );
Ogre::Root::getSingleton( ).addFrameListener( this );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_FAILURE( "GUIManager - error when creating gui. Message: " << ex.getMessage( ).c_str( ) );
throw Ember::Exception( ex.getMessage( ).c_str( ) );
}
}
191 GUIManager::~GUIManager( )
{
S_LOG_INFO( "Shutting down GUI manager." );
WidgetStore widgetStoreCopy( mWidgets );
for ( WidgetStore::iterator I = widgetStoreCopy.begin( ); I != widgetStoreCopy.end( ); ++I ) {
S_LOG_INFO( "Deleting widget " << ( *I )->getPrefix( ) << "." );
delete *I;
}
delete mActiveWidgetHandler;
delete mEntityIconManager;
delete mIconManager;
delete mGuiSystem;
Ogre::Root::getSingleton( ).removeFrameListener( this );
delete mCEGUIAdapter;
delete mEntityWorldPickListener;
delete mPicker;
delete mGuiRenderer;
delete mLuaScriptModule;
//delete mMousePicker;
//mMousePicker = 0;
}
218 void GUIManager::initialize( )
{
Ember::ConfigService* configSrv = Ember::EmberServices::getSingletonPtr( )->getConfigService( );
chdir( configSrv->getEmberDataDirectory( ).c_str( ) );
try {
mDebugText = ( CEGUI::GUISheet* )mWindowManager->createWindow( "DefaultGUISheet", ( CEGUI::utf8* )"DebugText" );
mSheet->addChildWindow( mDebugText );
mDebugText->setMaxSize( CEGUI::UVector2( UDim( 1.0f, 0 ), UDim( 0, 25 ) ) );
mDebugText->setPosition( CEGUI::UVector2( UDim( 0.0f, 0 ), UDim( 1.0f, -25 ) ) );
mDebugText->setSize( CEGUI::UVector2( UDim( 1.0f, 0 ), UDim( 0, 25 ) ) );
/* mDebugText->setFrameEnabled( false );
mDebugText->setBackgroundEnabled( false );*/
//stxt->setHorizontalFormatting( StaticText::WordWrapCentred );
//the console and quit widgets are not lua scripts, and should be loaded explicit
// mConsoleWidget = static_cast<ConsoleWidget*>( createWidget( "ConsoleWidget" ) );
// if ( !mConsoleWidget ) {
// throw Ember::Exception( "Could not create console widget." );
// }
createWidget( "Quit" );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "GUIManager - error when initializing widgets: " << e.what( ) );
throw e;
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "GUIManager - error when initializing widgets: " << e.getMessage( ).c_str( ) );
throw e;
}
try {
mIconManager = new Gui::Icons::IconManager( );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "GUIManager - error when creating icon manager: " << e.what( ) );
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "GUIManager - error when creating icon manager: " << e.getMessage( ).c_str( ) );
}
try {
mEntityIconManager = new Gui::EntityIconManager( *this );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "GUIManager - error when creating entity icon manager: " << e.what( ) );
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "GUIManager - error when creating entity icon manager: " << e.getMessage( ).c_str( ) );
}
std::vector<std::string> widgetsToLoad;
widgetsToLoad.push_back( "StatusIconBar" );
widgetsToLoad.push_back( "IngameChatWidget" );
// widgetsToLoad.push_back( "InventoryWidget" );
widgetsToLoad.push_back( "InspectWidget" );
widgetsToLoad.push_back( "MakeEntityWidget" );
widgetsToLoad.push_back( "JesusEdit" );
widgetsToLoad.push_back( "ServerWidget" );
widgetsToLoad.push_back( "Help" );
widgetsToLoad.push_back( "MeshPreview" );
///this should be defined in some kind of text file, which should be different depending on what game you're playing ( like mason )
try {
///load the bootstrap script which will load all other scripts
Ember::EmberServices::getSingleton( ).getScriptingService( )->loadScript( "lua/Bootstrap.lua" );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "Error when loading bootstrap script. Error message: " << e.what( ) );
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "Error when loading bootstrap script. Error message: " << e.getMessage( ).c_str( ) );
}
for ( std::vector<std::string>::iterator I = widgetsToLoad.begin( ); I != widgetsToLoad.end( ); ++I ) {
try {
S_LOG_VERBOSE( "Loading widget " << *I );
createWidget( *I );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "Error when initializing widget " << *I << " : " << e.what( ) );
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "Error when initializing widget " << *I << " : " << e.getMessage( ).c_str( ) );
}
}
}
298 void GUIManager::scriptingServiceStopping( )
{
mGuiSystem->setScriptingModule( 0 );
delete mLuaScriptModule;
mLuaScriptModule = 0;
}
305 void GUIManager::EmitEntityAction( const std::string& action, EmberEntity* entity )
{
EventEntityAction.emit( action, entity );
}
311 CEGUI::Window* GUIManager::createWindow( const std::string& windowType )
{
std::stringstream ss;
ss << "_autoWindow_" << ( msAutoGenId++ );
return createWindow( windowType, ss.str( ) );
}
318 CEGUI::Window* GUIManager::createWindow( const std::string& windowType, const std::string& windowName )
{
try {
CEGUI::Window* window = mWindowManager->createWindow( windowType, windowName );
return window;
} catch ( const CEGUI::Exception& ex ) {
S_LOG_FAILURE( "Error when creating new window of type " << windowType << " with name " << windowName << ".\n" << ex.getMessage( ).c_str( ) );
return 0;
} catch ( const std::exception& ex ) {
S_LOG_FAILURE( "Error when creating new window of type " << windowType << " with name " << windowName << ".\n" << ex.what( ) );
return 0;
}
}
332 Widget* GUIManager::createWidget( )
{
return createWidget( "Widget" );
}
337 Widget* GUIManager::createWidget( const std::string& name )
{
Widget* widget( 0 );
try {
widget = WidgetLoader::createWidget( name );
if ( widget == 0 ) {
S_LOG_FAILURE( "Could not find widget with name " << name );
return 0;
}
widget->init( this );
widget->buildWidget( );
addWidget( widget );
S_LOG_INFO( "Successfully loaded widget " << name );
} catch ( const std::exception& e ) {
S_LOG_FAILURE( "Error when loading widget " << name << ": " << e.what( ) );
return 0;
} catch ( const CEGUI::Exception& e ) {
S_LOG_FAILURE( "Error when loading widget " << name << ": " << e.getMessage( ).c_str( ) );
return 0;
}
return widget;
}
361 void GUIManager::destroyWidget( Widget* widget )
{
if ( !widget )
{
S_LOG_WARNING( "Trying to destroy null widget." );
return;
}
removeWidget( widget );
delete widget;
}
373 void GUIManager::setDebugText( const std::string& text )
{
if ( mDebugText )
{
mDebugText->setText( text );
}
}
381 Input& GUIManager::getInput( ) const
{
return Input::getSingleton( );
}
387 CEGUI::Window* GUIManager::getMainSheet( ) const
{
return mSheet;
}
392 void GUIManager::removeWidget( Widget* widget )
{
WidgetStore::iterator I = std::find( mWidgets.begin( ), mWidgets.end( ), widget );
if ( I != mWidgets.end( ) ) {
mWidgets.erase( I );
}
}
400 void GUIManager::addWidget( Widget* widget )
{
mWidgets.push_back( widget );
}
410 bool GUIManager::frameStarted( const Ogre::FrameEvent& evt )
{
try {
CEGUI::System::getSingleton( ).injectTimePulse( evt.timeSinceLastFrame );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
// if ( mPreviousInputMode == IM_GUI ) {
// if ( !mInput->getInputMode( ) ) {
// EventInputModeChanged.emit( IM_MOVEMENT );
// mPreviousInputMode = IM_MOVEMENT;
// }
// } else {
// if ( mInput->isInGUIMode( ) ) {
// EventInputModeChanged.emit( IM_GUI );
// mPreviousInputMode = IM_GUI;
// }
// }
//iterate over all widgets and send them a frameStarted event
WidgetStore::iterator I = mWidgets.begin( );
WidgetStore::iterator I_end = mWidgets.end( );
for ( ; I != I_end; ++I ) {
Widget* aWidget = *I;
try {
aWidget->frameStarted( evt );
} catch ( const CEGUI::Exception& ex ) {
S_LOG_WARNING( "Error in CEGUI: " << ex.getMessage( ).c_str( ) );
}
}
EventFrameStarted.emit( evt.timeSinceLastFrame );
return true;
}
451 bool GUIManager::mSheet_MouseButtonDown( const CEGUI::EventArgs& args )
{
if ( isInGUIMode( ) ) {
const CEGUI::MouseEventArgs& mouseArgs = static_cast<const CEGUI::MouseEventArgs&>( args );
S_LOG_VERBOSE( "Main sheet is capturing input" );
CEGUI::Window* aWindow = CEGUI::Window::getCaptureWindow( );
if ( aWindow ) {
aWindow->releaseInput( );
aWindow->deactivate( );
}
//mSheet->activate( );
//mSheet->captureInput( );
if ( mPicker ) {
const CEGUI::Point& position = CEGUI::MouseCursor::getSingleton( ).getDisplayIndependantPosition( );
MousePickerArgs pickerArgs;
pickerArgs.windowX = mouseArgs.position.d_x;
pickerArgs.windowY = mouseArgs.position.d_y;
pickerArgs.pickType = MPT_CLICK;
mPicker->doMousePicking( position.d_x, position.d_y, pickerArgs );
}
}
return true;
}
478 bool GUIManager::mSheet_MouseDoubleClick( const CEGUI::EventArgs& args )
{
const CEGUI::MouseEventArgs& mouseArgs = static_cast<const CEGUI::MouseEventArgs&>( args );
S_LOG_VERBOSE( "Main sheet double click." );
CEGUI::Window* aWindow = CEGUI::Window::getCaptureWindow( );
if ( aWindow ) {
aWindow->releaseInput( );
aWindow->deactivate( );
}
//mSheet->activate( );
//mSheet->captureInput( );
if ( mPicker ) {
const CEGUI::Point& position = CEGUI::MouseCursor::getSingleton( ).getDisplayIndependantPosition( );
MousePickerArgs pickerArgs;
pickerArgs.windowX = mouseArgs.position.d_x;
pickerArgs.windowY = mouseArgs.position.d_y;
pickerArgs.pickType = MPT_DOUBLECLICK;
mPicker->doMousePicking( position.d_x, position.d_y, pickerArgs );
}
return true;
}
504 bool GUIManager::mSheet_CaptureLost( const CEGUI::EventArgs& args )
{
S_LOG_VERBOSE( "Main sheet lost input" );
return true;
}
510 const bool GUIManager::isInMovementKeysMode( ) const {
return mSheet->isCapturedByThis( ) || !isInGUIMode( );
}
514 const bool GUIManager::isInGUIMode( ) const {
return getInput( ).getInputMode( ) == Input::IM_GUI;
}
518 void GUIManager::pressedKey( const SDL_keysym& key, Input::InputMode inputMode )
{
if ( ( key.mod & KMOD_CTRL || key.mod & KMOD_LCTRL || key.mod & KMOD_RCTRL ) && ( key.sym == SDLK_c || key.sym == SDLK_x ) ) {
bool cut = ( key.sym == SDLK_x );
CEGUI::Window* active = mSheet->getActiveChild( );
if ( !active ) return;
CEGUI::String seltext;
const CEGUI::String& type = active->getType( );
if ( type.find( "/MultiLineEditbox" ) != CEGUI::String::npos ) {
CEGUI::MultiLineEditbox* edit = static_cast<CEGUI::MultiLineEditbox*>( active );
CEGUI::String::size_type beg = edit->getSelectionStartIndex( );
CEGUI::String::size_type len = edit->getSelectionLength( );
seltext = edit->getText( ).substr( beg, len ).c_str( );
// are we cutting or just copying?
if ( cut ) {
if ( edit->isReadOnly( ) ) return;
CEGUI::String newtext = edit->getText( );
edit->setText( newtext.erase( beg, len ) );
}
} else if ( type.find( "/Editbox" ) != CEGUI::String::npos ) {
CEGUI::Editbox* edit = static_cast<CEGUI::Editbox*>( active );
CEGUI::String::size_type beg = edit->getSelectionStartIndex( );
CEGUI::String::size_type len = edit->getSelectionLength( );
seltext = edit->getText( ).substr( beg, len ).c_str( );
// are we cutting or just copying?
if ( cut ) {
if ( edit->isReadOnly( ) ) return;
CEGUI::String newtext = edit->getText( );
edit->setText( newtext.erase( beg, len ) );
}
}
getInput( ).writeToClipboard( seltext.c_str( ) );
}
}
561 void GUIManager::runCommand( const std::string &command, const std::string &args )
{
if ( command == ToggleInputMode.getCommand( ) ) {
getInput( ).toggleInputMode( );
} else if ( command == ReloadGui.getCommand( ) ) {
Ogre::TextureManager* texMgr = Ogre::TextureManager::getSingletonPtr( );
Ogre::ResourcePtr resource = texMgr->getByName( "cegui/" + getDefaultScheme( ) + ".png" );
if ( !resource.isNull( ) ) {
resource->reload( );
}
}
}
// void GUIManager::pushMousePicker( MousePicker * mousePicker )
// {
// mMousePickers.push( mousePicker );
// }
// MousePicker * GUIManager::popMousePicker( )
// {
// ///only pop if there's more than one registered picker
// if ( mMousePickers.size( ) > 1 )
// mMousePickers.pop( );
// return mMousePickers.top( );
// }
587 void GUIManager::EmberOgre_CreatedAvatarEntity( AvatarEmberEntity* entity )
{
///switch to movement mode, since it appears most people don't know how to change from gui mode
getInput( ).setInputMode( Input::IM_MOVEMENT );
}
593 void GUIManager::EmberOgre_AvatarControllerCreated( AvatarController& controller )
{
EmberOgre::getSingleton( ).getMainCamera( )->pushWorldPickListener( mEntityWorldPickListener );
}
598 const std::string& GUIManager::getLayoutDir( ) const
{
static std::string dir( "cegui/datafiles/layouts/" );
return dir;
}
604 const std::string& GUIManager::getDefaultScheme( ) const
{
return mDefaultScheme;
}
609 EntityWorldPickListener* GUIManager::getEntityPickListener( ) const
{
return mEntityWorldPickListener;
}
614 Gui::Icons::IconManager* GUIManager::getIconManager( )
{
return mIconManager;
}
619 Gui::EntityIconManager* GUIManager::getEntityIconManager( )
{
return mEntityIconManager;
}
}
1 /*
Copyright ( C ) 2004 Miguel Guzman ( Aglanor )
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef GUIMANAGER_H
#define GUIMANAGER_H
#include "EmberOgrePrerequisites.h"
#include <CEGUIBase.h>
#include <OgreCEGUIRenderer.h>
#include <sigc++/trackable.h>
#include "framework/Singleton.h"
#include <SDL.h>
#include <stack>
#include "framework/ConsoleObject.h"
#include "input/Input.h"
#include "input/InputCommandMapper.h"
namespace CEGUI
{
42 class GUISheet;
43 class LuaScriptModule;
}
namespace Ember {
47 class IScriptingProvider;
}
50 namespace EmberOgre {
class EmberEntity;
class TerrainGenerator;
class CEGUI::Window;
class MousePicker;
class Input;
class AvatarEmberEntity;
class GUICEGUIAdapter;
class EntityWorldPickListener;
class AvatarController;
namespace Gui {
class Widget;
class EntityIconManager;
class ActiveWidgetHandler;
namespace Icons {
class IconManager;
}
}
/**
* This class will be responsible for all the GUI related things
*/
class GUIManager :
public Ember::Singleton<GUIManager>,
Ogre::FrameListener,
public sigc::trackable,
public Ember::ConsoleObject
{
public:
typedef std::vector<Gui::Widget*> WidgetStore;
static const std::string SCREENSHOT;
static const std::string TOGGLEINPUTMODE;
GUIManager( Ogre::RenderWindow* window, Ogre::SceneManager* sceneMgr );
virtual ~GUIManager( );
sigc::signal<void, const std::string&, EmberEntity*> AppendIGChatLine;
sigc::signal<void, const std::string&, EmberEntity*> AppendOOGChatLine;
sigc::signal<void, const std::string&> AppendAvatarImaginary;
sigc::signal<void, const std::string&, EmberEntity*> EventEntityAction;
/**
Emitted every frame.
*/
sigc::signal<void, float> EventFrameStarted;
/**
* Emits an action for a certain entity.
* An action could be something like "touch" or "inspect".
* @param action
*/
void EmitEntityAction( const std::string& action, EmberEntity* entity );
/**
* Removed a widget from the system.
* @param widget
*/
void removeWidget( Gui::Widget* widget );
/**
* Adds a new widget to the system. This means it will recieve FrameStarted events.
* @param widget
*/
void addWidget( Gui::Widget* widget );
/**
* Called by Ogre each frame.
* @param evt
* @return
*/
bool frameStarted( const Ogre::FrameEvent& evt );
/**
* Gets the root sheet of the CEGUI windowing system.
* @return
*/
CEGUI::Window* getMainSheet( ) const;
/**
* Called by EmberOgre at initialization.
*/
void initialize( );
/**
* sets a text to be shown somewhere on the screen, used for debugging purposes
* @param text
*/
void setDebugText( const std::string& text );
/**
* true if we're in GUI mode, which means that input events will be sent to the CEGUI system instead of the "world"
* @return
*/
const bool isInGUIMode( ) const;
/**
* true if keyboard input should make the avatar move
* this happens when wither 1 ) we're not in gui mode 2 ) the background sheet has the input control ( thus, when something else, like an edit box has input control, that edit box will recieve key strokes
* @return
*/
const bool isInMovementKeysMode( ) const;
/**
* Gets the currently active MousePicker instance.
* @return
*/
inline MousePicker* getMousePicker( ) { return mMousePickers.top( ); }
/**
* accessor for the Input instance object
* @return
*/
Input& getInput( ) const;
/**
* Pushes a new mouse picker onto the stack, "pushing down" the current mouse picker.
* @param mousePicker
*/
// void pushMousePicker( MousePicker* mousePicker );
/**
* Pops the current mouse picker from the stack and returns the next in line.
* It's not possible to empty the stack. If there's only one picker left, no popping will be done, and the last picker will be returned.
* @return
*/
// MousePicker* popMousePicker( );
inline CEGUI::OgreCEGUIRenderer* getGuiRenderer( ) const {return mGuiRenderer;}
/**
* Reimplements the ConsoleObject::runCommand method
* @param command
* @param args
*/
virtual void runCommand( const std::string &command, const std::string &args );
/**
* returns the path to the directory where all layouts are stored
* @return
*/
const std::string& getLayoutDir( ) const;
/**
Creates a new window of the supplied type, giving it an autogenerated, unique name.
*/
CEGUI::Window* createWindow( const std::string& windowType );
/**
Creates a new window of the supplied type with the supplied name.
*/
CEGUI::Window* createWindow( const std::string& windowType, const std::string& windowName );
/**
* Creates a new Widget
* @return
*/
Gui::Widget* createWidget( );
/**
* creates a widget
* @see WidgetLoader
* @param name the type of widget to create
* @return
*/
Gui::Widget* createWidget( const std::string& name );
/**
* Destroys a widget previously created by createWidget
* @param widget The widget to destroy.
*/
void destroyWidget( Gui::Widget* widget );
/**
* Gets the name of the default scheme used ( such as "EmberLook" or "WindowsLook" )
* @return
*/
const std::string& getDefaultScheme( ) const;
EntityWorldPickListener* getEntityPickListener( ) const;
/**
Command for toggling between the input modes.
*/
const Ember::ConsoleCommandWrapper ToggleInputMode;
/**
Command for reloading the gui.
*/
const Ember::ConsoleCommandWrapper ReloadGui;
/**
* Accessor for the IconManager which handles low level icons.
* @return The main IconManager
*/
Gui::Icons::IconManager* getIconManager( );
/**
* Accessor for the EntityIconManager, which handles entity icons and slots.
* @return The main EntityIconManager
*/
Gui::EntityIconManager* getEntityIconManager( );
protected:
/**
Counter for autonaming of windows.
*/
static unsigned long msAutoGenId;
InputCommandMapper mGuiCommandMapper;
MousePicker* mPicker;
EntityWorldPickListener* mEntityWorldPickListener;
CEGUI::Window* mSheet;
CEGUI::WindowManager* mWindowManager;
CEGUI::GUISheet* mDebugText;
Ogre::RenderWindow* mWindow;
CEGUI::System* mGuiSystem;
CEGUI::OgreCEGUIRenderer* mGuiRenderer;
std::string mDefaultScheme;
/**
all loaded widgets are stored here
*/
WidgetStore mWidgets;
/**
A stack of the mouse pickers used. This allows for a component to "push down" the current mouse picker in favor of its own
*/
std::stack<MousePicker*> mMousePickers;
//events
bool mSheet_MouseButtonDown( const CEGUI::EventArgs& args );
bool mSheet_MouseDoubleClick( const CEGUI::EventArgs& args );
bool mSheet_CaptureLost( const CEGUI::EventArgs& args );
/**
* hooked to EmberOgre::EventCreatedAvatarEntity, switches the input mode to movement mode
* @param entity
*/
void EmberOgre_CreatedAvatarEntity( AvatarEmberEntity* entity );
/**
* hooked to EmberOgre::EventAvatarControllerCreated, connects the mEntityWorldPickListener to the main AvatarCamera
* @param controller
*/
void EmberOgre_AvatarControllerCreated( AvatarController& controller );
// InputMode mPreviousInputMode;
void pressedKey( const SDL_keysym& key, Input::InputMode inputMode );
/**
Adapter for CEGUI which will send input events to CEGUI
*/
GUICEGUIAdapter* mCEGUIAdapter;
CEGUI::LuaScriptModule* mLuaScriptModule;
void scriptingServiceStopping( );
Gui::Icons::IconManager* mIconManager;
Gui::EntityIconManager* mEntityIconManager;
Gui::ActiveWidgetHandler* mActiveWidgetHandler;
};
}
#endif
1 //
// C++ Interface: IWorldPickListener
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2006
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREIWORLDPICKLISTENER_H
#define EMBEROGREIWORLDPICKLISTENER_H
#include "EmberOgrePrerequisites.h"
namespace EmberOgre {
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
/**
The kind of mouse click operation.
*/
enum MousePickType
{
///Simple click
MPT_CLICK = 1,
///Double click
MPT_DOUBLECLICK = 2
};
/**
Mouse picking info from the windowing system.
*/
struct MousePickerArgs
{
/**
The x and y coords in local window space.
*/
float windowX, windowY;
MousePickType pickType;
};
60 class IWorldPickListener
{
public:
64 virtual ~IWorldPickListener( ) {}
/**
Called at the start of a picking context. This allows the pickers to be reset and to keep state for each picking.
*/
69 virtual void initializePickingContext( ) {}
/**
Called when the picking is over, either because one of the processPickResult calls set continuePicking to false, or because there are no more objects to pick.
*/
74 virtual void endPickingContext( const MousePickerArgs& mousePickerArgs ) {}
/**
* Processes the pick result.
* This will be called for each picked object.
* @param continuePicking set this to false if you don't want to process any more pick results, or don't want any other IWorldPickListener to process the pick any more
* @param entry The actual pick entry.
* @param cameraRay The ray which resulted in the pick.
* @param mousePickerArgs The original mouse picker arguments.
*/
84 virtual void processPickResult( bool& continuePicking, Ogre::RaySceneQueryResultEntry& entry, Ogre::Ray& cameraRay, const MousePickerArgs& mousePickerArgs ) = 0;
};
}
#endif
1 /*
-----------------------------------------------------------------------------
MathConverter.h by Miguel Guzman Miranda ( Aglanor )
Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2005
Copyright © 2003 The Worldforge Project ( http://www.worldforge.org )
This file is part of Ember client ( http://www.worldforge.org/dev/eng/clients/Ember )
This code is distributed under the GNU GPL ( General Public License ).
See file COPYING for details.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Filename: MathConverter.h
Description: Point, Vector and Quaternion converter
for world-centric coordinates ( Atlas-wfmath like )
to/from screen-centric coordinates ( Ogre like ).
Atlas is World-centric ( picture a map ):
x is east
y is north
z is up
Ogre is screen-centric ( picture your monitor screen ):
x is right
y is up
z is depth ( negative towards the screen,
positive is towards you,
so the coord system is also dextrogyrous )
--------------------------------------------------------
Example of Atlas --> Ogre conversion
Picture this is the world map, in both cases:
^ North
|
| East
( Up )--->
Atlas Ogre
^ a.y ^ -o.z
| |
| a.x | o.x
( a.z )---> ( o.y )--->
--------------------------------------------------------
Example of Ogre --> Atlas conversion
Picture this is your computer screen, in both cases:
^ Up
|
| Left
( You )--->
Ogre Atlas
^ o.y ^ a.z
| |
| o.x | a.x
( o.z )---> ( -a.y )--->
The math is:
Atlas.x = Ogre.x
Atlas.y = -Ogre.z
Atlas.z = Ogre.y
Ogre.x = Atlas.x
Ogre.y = Atlas.z
Ogre.z = -Atlas.y
-----------------------------------------------------------------------------
*/
#ifndef __MATH_CONVERTER_H__
#define __MATH_CONVERTER_H__
// ------------------------------
// Include WFmath header files
// ------------------------------
#include <wfmath/point.h>
#include <wfmath/vector.h>
#include <wfmath/axisbox.h>
#include <wfmath/quaternion.h>
#include <wfmath/const.h>
#include <math.h>
namespace EmberOgre {
typedef WFMath::Point<2> TerrainPosition;
// //note that this will ignore the y value of the supplied ogre vector
// inline TerrainPosition Ogre2Atlas( Ogre::Vector3& p ) {
// return WFMath::Point<2>( p.x, -p.z );
// }
/*inline Ogre::Vector3 Atlas2Ogre( TerrainPosition& p ) {
return Ogre::Vector3( p.x( ), 0, -p.y( ) );
}*/
104 inline Ogre::Vector3 Atlas2Ogre( const TerrainPosition& p ) {
return Ogre::Vector3( p.x( ), 0, -p.y( ) );
}
108 inline Ogre::Vector2 Atlas2Ogre_Vector2( const TerrainPosition& p ) {
return Ogre::Vector2( p.x( ), -p.y( ) );
}
// inline WFMath::Point<3> Ogre2Atlas( Ogre::Vector3& p ) {
// return WFMath::Point<3>( p.x, -p.z, p.y );
// }
/*inline WFMath::Vector<3> Ogre2Atlas_Vector3( Ogre::Vector3& p ) {
return WFMath::Vector<3>( p.x, -p.z, p.y );
}*/
119 inline WFMath::Point<3> Ogre2Atlas( const Ogre::Vector3& p ) {
return WFMath::Point<3>( p.x, -p.z, p.y );
}
123 inline TerrainPosition Ogre2Atlas( const Ogre::Vector2& p ) {
return TerrainPosition( p.x, -p.y );
}
127 inline TerrainPosition Ogre2Atlas_TerrainPosition( const Ogre::Vector3& p ) {
return TerrainPosition( p.x, -p.z );
}
131 inline WFMath::Vector<3> Ogre2Atlas_Vector3( const Ogre::Vector3& p ) {
return WFMath::Vector<3>( p.x, -p.z, p.y );
}
// inline Ogre::Vector3 Atlas2Ogre( WFMath::Point<3>& p ){
// return Ogre::Vector3( p.x( ), p.z( ), -p.y( ) );
// }
139 inline Ogre::Vector3 Atlas2Ogre( const WFMath::Point<3>& p ){
return Ogre::Vector3( p.x( ), p.z( ), -p.y( ) );
}
// inline Ogre::Vector3 Atlas2Ogre( WFMath::Vector<3>& v ){
// return Ogre::Vector3( v.x( ), v.z( ), -v.y( ) );
// }
147 inline Ogre::Vector3 Atlas2Ogre( const WFMath::Vector<3>& v ){
return Ogre::Vector3( v.x( ), v.z( ), -v.y( ) );
}
// inline Ogre::Quaternion Atlas2Ogre( WFMath::Quaternion& aq ){
// if ( !aq.isValid( ) ) {
// return Ogre::Quaternion::IDENTITY;
// }
// return Ogre::Quaternion( aq.scalar( ), aq.vector( ).x( ), aq.vector( ).z( ), -aq.vector( ).y( ) );
// }
158 inline Ogre::Quaternion Atlas2Ogre( const WFMath::Quaternion& aq ){
if ( !aq.isValid( ) ) {
return Ogre::Quaternion::IDENTITY;
}
return Ogre::Quaternion( aq.scalar( ), aq.vector( ).x( ), aq.vector( ).z( ), -aq.vector( ).y( ) );
}
//is this correct?
// inline WFMath::Quaternion Ogre2Atlas( Ogre::Quaternion& aq ){
// return WFMath::Quaternion( aq.w, aq.x, -aq.z, aq.y );
// }
169 inline WFMath::Quaternion Ogre2Atlas( const Ogre::Quaternion& aq ){
return WFMath::Quaternion( aq.w, aq.x, -aq.z, aq.y );
}
173 inline Ogre::AxisAlignedBox Atlas2Ogre( const WFMath::AxisBox<3>& axisBox ){
if ( !axisBox.isValid( ) ) {
return Ogre::AxisAlignedBox( );
}
return Ogre::AxisAlignedBox( axisBox.lowCorner( ).x( ), axisBox.lowCorner( ).z( ), -axisBox.highCorner( ).y( ), axisBox.highCorner( ).x( ), axisBox.highCorner( ).z( ), -axisBox.lowCorner( ).y( ) );
}
180 inline Ogre::TRect<Ogre::Real> Atlas2Ogre( const WFMath::AxisBox<2>& atlasBox ) {
if ( !atlasBox.isValid( ) ) {
return Ogre::TRect<Ogre::Real>( );
}
return Ogre::TRect<Ogre::Real>( atlasBox.lowCorner( ).x( ), -atlasBox.highCorner( ).y( ), atlasBox.highCorner( ).x( ), -atlasBox.lowCorner( ).y( ) );
}
188 inline WFMath::AxisBox<3> Ogre2Atlas( const Ogre::AxisAlignedBox& axisBox ){
if ( axisBox.isNull( ) || axisBox.isInfinite( ) ) {
return WFMath::AxisBox<3>( );
}
return WFMath::AxisBox<3>( WFMath::Point<3>( axisBox.getMinimum( ).x, axisBox.getMinimum( ).z, -axisBox.getMaximum( ).y ), WFMath::Point<3>( axisBox.getMaximum( ).x, axisBox.getMaximum( ).z, -axisBox.getMinimum( ).y ) );
}
}
/*
Ogre::Vector3 Ogre::Vector3( WFMath::Vector<3> v ) {
return Ogre::Vector3( v.x( ), v.z( ), -v.y( ) );
}
WFMath::Point<3>::operator Ogre::Vector3( ) const{
return Ogre::Vector3( this.x( ), this.z( ), -this.y( ) );
}
*/
#endif
1 /*
ConsoleObjectImpl.cpp by Miguel Guzman ( Aglanor )
Copyright ( C ) 2002 Miguel Guzman & The Worldforge Project
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// config headers
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// system headers
// library headers
#include "EmberOgrePrerequisites.h"
// local headers
#include "MediaDeployer.h"
namespace EmberOgre {
//TODO: add a sequence for mediadeployer ids
//TODO: add several methods for adding media with different params
MediaDeployer* MediaDeployer::_mediaDeployerInstance = 0;
40 MediaDeployer & MediaDeployer::getSingleton( void )
{
if( _mediaDeployerInstance == 0 )
_mediaDeployerInstance = new MediaDeployer;
return *_mediaDeployerInstance;
}
47 MediaDeployer::MediaDeployer( void )
{
mSceneMgr = Ogre::Root::getSingleton( ).getSceneManager( Ogre::ST_EXTERIOR_CLOSE );
}
52 MediaDeployer::~MediaDeployer( )
{
}
57 bool MediaDeployer::addMedia( std::string modelName )
{
return true;
}
62 bool MediaDeployer::addMedia( std::string modelName, std::string id, Ogre::Vector3 position )
{
// create the ogre node and entity
Ogre::SceneNode* ogreNode = static_cast<Ogre::SceneNode*>( mSceneMgr->getRootSceneNode( )->createChild( ) );
Ogre::Entity* ogreEntity;
ogreEntity = mSceneMgr->createEntity( id, modelName );
ogreNode->setPosition( position );
ogreNode->attachObject( ogreEntity );
return true;
}
}
1 /*
ConsoleObjectImpl.h by Miguel Guzman ( Aglanor )
Copyright ( C ) 2002 Miguel Guzman & The Worldforge Project
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __EmberOgre_MediaDeployer_H__
#define __EmberOgre_MediaDeployer_H__
namespace EmberOgre {
25 class MediaDeployer
{
public:
30 ~MediaDeployer( );
32 static MediaDeployer & getSingleton( void );
34 bool addMedia( std::string );
35 bool addMedia( std::string, std::string, Ogre::Vector3 );
private:
/**
* Private constructor ( for singleton )
*/
42 MediaDeployer( void );
/**
* Instance variable for singleton console object implementation.
*/
static MediaDeployer* _mediaDeployerInstance;
/**
* Scene manager to which deploy the media
*/
52 Ogre::SceneManager* mSceneMgr;
}; // End of class declaration
}
#endif
1 //
// C++ Implementation: MediaUpdater
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#include "MediaUpdater.h"
#include "services/EmberServices.h"
#include "services/config/ConfigService.h"
#include "services/wfut/WfutService.h"
namespace EmberOgre {
31 MediaUpdater::MediaUpdater( )
{
}
36 MediaUpdater::~MediaUpdater( )
{
}
40 void MediaUpdater::performUpdate( )
{
Ember::ConfigService* configSrv = Ember::EmberServices::getSingleton( ).getConfigService( );
Ember::WfutService* wfutSrv= Ember::EmberServices::getSingleton( ).getWfutService( );
if ( configSrv->itemExists( "wfut", "server" ) ) {
std::string server( configSrv->getValue( "wfut", "server" ) );
if ( configSrv->itemExists( "wfut", "channel" ) ) {
std::string channel( configSrv->getValue( "wfut", "channel" ) );
wfutSrv->startUpdate( server, channel, configSrv->getHomeDirectory( ) , "" );
while ( wfutSrv->poll( ) ) {
}
}
}
}
}
1 //
// C++ Interface: MediaUpdater
//
// Description:
//
//
// Author: Erik Hjortsberg <erik@katastrof.nu>, ( C ) 2007
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifndef EMBEROGREMEDIAUPDATER_H
#define EMBEROGREMEDIAUPDATER_H
namespace EmberOgre {
/**
@author Erik Hjortsberg <erik@katastrof.nu>
*/
31 class MediaUpdater{
public:
33 MediaUpdater( );
35 ~MediaUpdater( );
37 void performUpdate( );
};
}
#endif
1 //
// C++ Implementation: MeshCollisionDetector
//
// Description:
//
//
// Author: Erik Hjortsberg <erik.hjortsberg@iteam.se>, ( C ) 2008
// This code is taked from http://www.ogre3d.org/wiki/index.php/Raycasting_to_the_polygon_level ( 2008-01-13 ), where it's released as Public Domain, and now relicensed to GPL. Author is unknown.
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "MeshCollisionDetector.h"
#include "EmberOgrePrerequisites.h"
#include "model/Model.h"
#include "model/SubModel.h"
namespace EmberOgre {
37 MeshCollisionDetector::MeshCollisionDetector( Model::Model* model )
:mModel( model )
{
}
43 MeshCollisionDetector::~MeshCollisionDetector( )
{
}
47 void MeshCollisionDetector::reload( )
{
}
51 void MeshCollisionDetector::refit( )
{
}
55 void MeshCollisionDetector::setVisualize( bool visualize )
{
}
58 bool MeshCollisionDetector::getVisualize( ) const
{
return false;
}
63 void MeshCollisionDetector::testCollision( Ogre::Ray& ray, CollisionResult& result )
{
// at this point we have raycast to a series of different objects bounding boxes.
// we need to test these different objects to see which is the first polygon hit.
// there are some minor optimizations ( distance based ) that mean we wont have to
// check all of the objects most of the time, but the worst case scenario is that
// we need to test every triangle of every object.
Ogre::Real closest_distance = -1.0f;
Ogre::Vector3 closest_result;
const Model::Model::SubModelSet& submodels = mModel->getSubmodels( );
for ( Model::Model::SubModelSet::const_iterator I = submodels.begin( ); I != submodels.end( ); ++I )
{
Ogre::Entity* pentity = ( *I )->getEntity( );
if ( pentity->isVisible( ) ) {
// mesh data to retrieve
size_t vertex_count;
size_t index_count;
Ogre::Vector3 *vertices;
unsigned long *indices;
// get the mesh information
getMeshInformation( pentity->getMesh( ), vertex_count, vertices, index_count, indices,
pentity->getParentNode( )->getWorldPosition( ),
pentity->getParentNode( )->getWorldOrientation( ),
pentity->getParentNode( )->getScale( ) );
// test for hitting individual triangles on the mesh
bool new_closest_found = false;
for ( int i = 0; i < static_cast<int>( index_count ); i += 3 )
{
// check for a hit against this triangle
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects( ray, vertices[indices[i]],
vertices[indices[i+1]], vertices[indices[i+2]], true, false );
// if it was a hit check if its the closest
if ( hit.first )
{
if ( ( closest_distance < 0.0f ) ||
( hit.second < closest_distance ) )
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true;
}
}
}
// free the verticies and indicies memory
delete[] vertices;
delete[] indices;
// if we found a new closest raycast for this object, update the
// closest_result before moving on to the next object.
if ( new_closest_found )
{
closest_result = ray.getPoint( closest_distance );
}
}
}
// return the result
if ( closest_distance >= 0.0f )
{
// raycast success
result.collided = true;
result.position = closest_result;
result.distance = closest_distance;
}
else
{
// raycast failed
result.collided = false;
}
}
// Get the mesh information for the given mesh.
// Code found on this forum link: http://www.ogre3d.org/wiki/index.php/RetrieveVertexData
143 void MeshCollisionDetector::getMeshInformation( const Ogre::MeshPtr mesh,
144 size_t &vertex_count,
145 Ogre::Vector3* &vertices,
146 size_t &index_count,
unsigned long* &indices,
148 const Ogre::Vector3 &position,
149 const Ogre::Quaternion &orient,
150 const Ogre::Vector3 &scale )
{
bool added_shared = false;
size_t current_offset = 0;
size_t shared_offset = 0;
size_t next_offset = 0;
size_t index_offset = 0;
vertex_count = index_count = 0;
// Calculate how many vertices and indices we're going to need
for ( unsigned short i = 0; i < mesh->getNumSubMeshes( ); ++i )
{
Ogre::SubMesh* submesh = mesh->getSubMesh( i );
// We only need to add the shared vertices once
if( submesh->useSharedVertices )
{
if( !added_shared )
{
vertex_count += mesh->sharedVertexData->vertexCount;
added_shared = true;
}
}
else
{
vertex_count += submesh->vertexData->vertexCount;
}
// Add the indices
index_count += submesh->indexData->indexCount;
}
// Allocate space for the vertices and indices
vertices = new Ogre::Vector3[vertex_count];
indices = new unsigned long[index_count];
added_shared = false;
// Run through the submeshes again, adding the data into the arrays
for ( unsigned short i = 0; i < mesh->getNumSubMeshes( ); ++i )
{
Ogre::SubMesh* submesh = mesh->getSubMesh( i );
Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
if( ( !submesh->useSharedVertices )||( submesh->useSharedVertices && !added_shared ) )
{
if( submesh->useSharedVertices )
{
added_shared = true;
shared_offset = current_offset;
}
const Ogre::VertexElement* posElem =
vertex_data->vertexDeclaration->findElementBySemantic( Ogre::VES_POSITION );
Ogre::HardwareVertexBufferSharedPtr vbuf =
vertex_data->vertexBufferBinding->getBuffer( posElem->getSource( ) );
unsigned char* vertex =
static_cast<unsigned char*>( vbuf->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ) );
// There is _no_ baseVertexPointerToElement( ) which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float* pReal;
for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize( ) )
{
posElem->baseVertexPointerToElement( vertex, &pReal );
Ogre::Vector3 pt( pReal[0], pReal[1], pReal[2] );
vertices[current_offset + j] = ( orient * ( pt * scale ) ) + position;