khanat-opennel-code/code/snowballs2/client/src/mouse_listener.cpp

474 lines
12 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Includes
//
#include <nel/misc/types_nl.h>
#include <nel/misc/event_server.h>
#include <nel/3d/u_driver.h>
#include <nel/3d/u_camera.h>
#include <nel/3d/u_visual_collision_entity.h>
#include <nel/3d/u_scene.h>
#include <nel/3d/u_instance.h>
#include <nel/misc/time_nl.h>
#include <nel/misc/quat.h>
#include <nel/misc/plane.h>
#include <nel/misc/config_file.h>
#include "snowballs_client.h"
#include "mouse_listener.h"
#include "entities.h"
#include "camera.h"
#include "landscape.h"
#include "network.h"
//
// Namespaces
//
using namespace NLMISC;
using namespace NL3D;
namespace SBCLIENT {
//
// Variables
//
static float MouseZoomStep;
static float GroundCamLimit = 0.5f;
//
// Functions
//
C3dMouseListener::C3dMouseListener()
{
// -- -- a mouse listener that can aim at the ground with a shape
// and does a bunch of other random things that should be
// done by something else, really
// -- -- half of this thing has to be split up into a
// CKeyboardControlledMovePrimitive or something
_Matrix.identity();
_ModelMatrix.identity() ;
_EnableModelMatrixEdition = false ;
_HotSpot.set (0,0,0);
_Viewport.initFullScreen();
_Frustrum.init (2.f, 2.f, -1.f, 1.f);
_MouseMode=nelStyle;
setSpeed (10.f);
_LastTime=CTime::getLocalTime ();
_ViewLagBehind = 20.0f;
_ViewHeight = 2.0f;
_ViewTargetHeight = 3.0f;
_AimingState = false;
_AimingDamage = 0.0f;
_AimingSpeed = 1.0f;
_AimingMax = 5.0f;
_AimingStartTime = 0;
_AimingRefreshRate = 100;
_AimingInstance = Scene->createInstance("aim.shape");
_AimingInstance.setTransformMode(UTransformable::RotQuat);
_X = 0.5f;
_Y = 0.5f;
_InvertedMouse = false;
}
C3dMouseListener::~C3dMouseListener()
{
// -- -- doesn't need to know about the snowballs specific global,
// scene shout be passed at construction to create aiming instance
// -- -- random note: aiminginstance here and aimingentity in landscape.cpp ...
// one of them obviously is in the wrong place
Scene->deleteInstance(_AimingInstance);
}
void C3dMouseListener::operator ()(const CEvent& event)
{
CEventMouse* mouseEvent=(CEventMouse*)&event;
if (event==EventMouseMoveId) // && mouseEvent->Button&leftButton!=0)
{
// Rotate Axis
CVector axis;
axis=_Matrix.getPos();
// First in the hotSpot
CMatrix comeFromHotSpot=_Matrix;
comeFromHotSpot.setPos (axis);
// Then turn along the Z axis with X mouse
CMatrix turnZ;
turnZ.identity();
turnZ.rotateZ ((float) Pi*2.f*(_X-mouseEvent->X));
// Then turn along the X axis with Y mouse
CMatrix turnX;
turnX.identity();
if (_InvertedMouse)
_ViewHeight += 3.0f*(mouseEvent->Y-_Y);
else
_ViewHeight -= 3.0f*(mouseEvent->Y-_Y);
// Then come back from hotspot
CMatrix goToHotSpot=comeFromHotSpot;
goToHotSpot.invert();
// Make the matrix
CMatrix negPivot, Pivot;
negPivot.identity();
negPivot.setPos (-axis);
Pivot.identity();
Pivot.setPos (axis);
// Make this transformation \\//
//_Matrix=Pivot*turnZ*negPivot*comeFromHotSpot*turnX*goToHotSpot*_Matrix;
Pivot*=turnZ;
Pivot*=negPivot;
Pivot*=comeFromHotSpot;
Pivot*=turnX;
Pivot*=goToHotSpot;
Pivot*=_Matrix;
_Matrix=Pivot;
// Normalize, too much transformation could give an ugly matrix..
_Matrix.normalize (CMatrix::XYZ);
// Update mouse position
Driver->setMousePos(0.5f, 0.5f);
_X = 0.5f;
_Y = 0.5f;
}
else if (event==EventMouseDownId)
{
// aim
_AimingState = true;
_AimingDamage = 0.0f;
_AimingStartTime = CTime::getLocalTime();
_AimingLastUpdateTime = 0;
}
else if (event==EventMouseUpId)
{
// throw snowball
// nlinfo("damage=%f", _AimingDamage);
_AimingState = false;
_AimingStartTime = 0;
CVector direction = (_AimedTarget-_AimingPosition).normed();
if (isOnline ())
{
sendSnowBall (Self->Id, _AimingPosition, _AimedTarget, SnowballSpeed, _AimingDamage);
}
else
{
shotSnowball (NextEID++, Self->Id, _AimingPosition, _AimedTarget, SnowballSpeed, _AimingDamage);
}
}
else if (event==EventMouseWheelId)
{
CEventMouseWheel* mouseEvent=(CEventMouseWheel*)&event;
_ViewLagBehind += (mouseEvent->Direction? -MouseZoomStep : +MouseZoomStep);
if (_ViewLagBehind < 2.0f)
_ViewLagBehind = 2.0f;
}
}
void C3dMouseListener::addToServer (CEventServer& server)
{
server.addListener (EventMouseMoveId, this);
server.addListener (EventMouseDownId, this);
server.addListener (EventMouseUpId, this);
server.addListener (EventMouseWheelId, this);
_AsyncListener.addToServer (server);
}
void C3dMouseListener::removeFromServer (CEventServer& server)
{
server.removeListener (EventMouseMoveId, this);
server.removeListener (EventMouseDownId, this);
server.removeListener (EventMouseUpId, this);
server.removeListener (EventMouseWheelId, this);
_AsyncListener.removeFromServer (server);
}
const NLMISC::CMatrix& C3dMouseListener::getViewMatrix ()
{
// Return the matrix
return _Matrix;
}
void C3dMouseListener::update()
{
// CVector
CVector dir (0,0,0);
bool find=false;
// -- -- what does the mouse listener have to do with the keyboard?!
// Key pushed ?
if (_AsyncListener.isKeyDown (KeyUP))
{
dir+=CVector (0, 1, 0);
find=true;
}
if (_AsyncListener.isKeyDown (KeyDOWN))
{
dir+=CVector (0, -1, 0);
find=true;
}
if (_AsyncListener.isKeyDown (KeyRIGHT))
{
dir+=CVector (1, 0, 0);
find=true;
}
if (_AsyncListener.isKeyDown (KeyLEFT))
{
dir+=CVector (-1, 0, 0);
find=true;
}
if (_AsyncListener.isKeyDown (KeyNEXT))
{
dir+=CVector (0, 0, -1);
find=true;
}
if (_AsyncListener.isKeyDown (KeyPRIOR))
{
dir+=CVector (0, 0, 1);
find=true;
}
// Character state setup
if (Self != NULL)
{
// modify the orientation depending on the straff
// The straff is determined by the keys that are down simultaneously
if (_AsyncListener.isKeyDown (KeyUP))
{
if (_AsyncListener.isKeyDown (KeyLEFT))
{
Self->AuxiliaryAngle = (float)Pi/4.0f;
}
else if (_AsyncListener.isKeyDown (KeyRIGHT))
{
Self->AuxiliaryAngle = -(float)Pi/4.0f;
}
else
{
Self->AuxiliaryAngle = 0;
}
_IsWalking = true;
}
else if (_AsyncListener.isKeyDown (KeyDOWN))
{
if (_AsyncListener.isKeyDown (KeyLEFT))
{
Self->AuxiliaryAngle = (float)Pi-(float)Pi/4.0f;
}
else if (_AsyncListener.isKeyDown (KeyRIGHT))
{
Self->AuxiliaryAngle = -(float)Pi+(float)Pi/4.0f;
}
else
{
Self->AuxiliaryAngle = (float)Pi;
}
_IsWalking = true;
}
else if (_AsyncListener.isKeyDown (KeyLEFT))
{
Self->AuxiliaryAngle = (float)Pi/2.0f;
_IsWalking = true;
}
else if (_AsyncListener.isKeyDown (KeyRIGHT))
{
Self->AuxiliaryAngle = -(float)Pi/2.0f;
_IsWalking = true;
}
else
{
_IsWalking = false;
}
if (isAiming())
Self->AuxiliaryAngle = 0.0f;
Self->IsAiming = isAiming();
Self->IsWalking = isWalking();
}
// if is aiming
if (_AimingState)
{
find = false;
TTime newTime = CTime::getLocalTime();
float delta = (float)(newTime-_AimingStartTime)/1000.0f;
_AimingDamage = _AimingSpeed*delta;
_AimingDamage = std::min(_AimingDamage, _AimingMax);
// if we have to update the aiming position
if (newTime - _AimingLastUpdateTime > _AimingRefreshRate)
{
// update the last target
_AimingLastUpdateTime = newTime;
// set up the aiming position
_AimingPosition = MouseListener->getPosition()+CVector(0.0f, 0.0f, 2.0f);
// compute the target
_AimedTarget = getTarget(_AimingPosition,
MouseListener->getViewDirection(),
100);
}
if (Self != NULL && !_AimingInstance.empty())
{
_AimingInstance.lookAt(MouseListener->getAimedTarget(), Camera.getMatrix().getPos());
float scale = MouseListener->getDamage();
_AimingInstance.setScale(scale, scale, scale);
_AimingInstance.show();
}
}
else
{
if (Self != NULL && !_AimingInstance.empty())
_AimingInstance.hide();
}
// key found ?
if (find)
{
// Time elapsed
uint32 milli=(uint32)(CTime::getLocalTime ()-_LastTime);
// Speed
float dPos=_Speed*(float)milli/1000.f;
// Good direction
dir.normalize ();
dir*=dPos;
// Orientation
dir=_Matrix.mulVector (dir);
// New position
_Matrix.setPos (_Matrix.getPos ()+dir);
}
// Last time
_LastTime=CTime::getLocalTime ();
}
void C3dMouseListener::setPosition(const CVector &position)
{
_Matrix.setPos(position);
}
NLMISC::CVector C3dMouseListener::getPosition() const
{
return _Matrix.getPos();
}
void C3dMouseListener::setOrientation(float angle)
{
/// todo
}
float C3dMouseListener::getOrientation()
{
CVector j = getViewMatrix().getJ();
j.z = 0.0f;
j.normalize();
return (float)atan2(j.y, j.x);
}
CVector C3dMouseListener::getViewDirection()
{
// float angle = getOrientation();
// return CVector((float)cos(angle), (float)sin(angle), (_ViewTar-_ViewHeight)/_ViewLagBehind).normed();
return Camera.getMatrix().getJ();
}
void C3dMouseListener::updateCamera()
{
CVector tpos = getPosition()+CVector(0.0f, 0.0f, _ViewTargetHeight);
CVector cpos = getPosition()+CVector(-(float)cos(getOrientation())*_ViewLagBehind, -(float)sin(getOrientation())*_ViewLagBehind, _ViewHeight);
CVector snapped = cpos,
normal;
if (CamCollisionEntity->snapToGround(snapped, normal) && (cpos.z-(snapped.z+GroundCamLimit))*normal.z < 0.0f)
{
cpos = snapped+CVector(0.0f, 0.0f, GroundCamLimit);
_ViewHeight = cpos.z - getPosition().z;
}
if (StereoHMD)
{
// look at straight forward
tpos.z = cpos.z;
}
_Camera.lookAt(cpos, tpos);
}
void cbUpdateMouseListenerConfig(CConfigFile::CVar &var)
{
if (var.Name == "MouseInvert") MouseListener->setInvertMouseMode(var.asInt() != 0);
else if (var.Name == "MouseZoomStep") MouseZoomStep = var.asFloat ();
else if (var.Name == "ViewLagBehind") MouseListener->setViewLagBehind(var.asFloat ());
else if (var.Name == "ViewHeight") MouseListener->setViewHeight(var.asFloat ());
else if (var.Name == "ViewTargetHeight") MouseListener->setViewTargetHeight(var.asFloat ());
else nlwarning ("Unknown variable update %s", var.Name.c_str());
}
void initMouseListenerConfig()
{
ConfigFile->setCallback ("MouseInvert", cbUpdateMouseListenerConfig);
ConfigFile->setCallback ("MouseZoomStep", cbUpdateMouseListenerConfig);
ConfigFile->setCallback ("ViewLagBehind", cbUpdateMouseListenerConfig);
ConfigFile->setCallback ("ViewHeight", cbUpdateMouseListenerConfig);
ConfigFile->setCallback ("ViewTargetHeight", cbUpdateMouseListenerConfig);
cbUpdateMouseListenerConfig(ConfigFile->getVar ("MouseInvert"));
cbUpdateMouseListenerConfig(ConfigFile->getVar ("MouseZoomStep"));
cbUpdateMouseListenerConfig(ConfigFile->getVar ("ViewLagBehind"));
cbUpdateMouseListenerConfig(ConfigFile->getVar ("ViewHeight"));
cbUpdateMouseListenerConfig(ConfigFile->getVar ("ViewTargetHeight"));
}
void releaseMouseListenerConfig()
{
ConfigFile->setCallback("MouseInvert", NULL);
ConfigFile->setCallback("MouseZoomStep", NULL);
ConfigFile->setCallback("ViewLagBehind", NULL);
ConfigFile->setCallback("ViewHeight", NULL);
ConfigFile->setCallback("ViewTargetHeight", NULL);
}
} /* namespace SBCLIENT */
/* end of file */