forked from bartvdbraak/blender
ee58d44945
With this fix the mouse actuator movement works well as with even screen resolutions as odd screen resolutions. Also it fixed the movement when the border of the blenderplayer window is out of the screen limits. Reviewed By: moguri Differential Revision: https://developer.blender.org/D946
537 lines
14 KiB
C++
537 lines
14 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Contributor(s): Geoffrey Gollmer, Jorge Bernal
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "KX_MouseActuator.h"
|
|
#include "KX_KetsjiEngine.h"
|
|
#include "SCA_MouseManager.h"
|
|
#include "SCA_IInputDevice.h"
|
|
#include "RAS_ICanvas.h"
|
|
#include "KX_GameObject.h"
|
|
#include "MT_Vector3.h"
|
|
#include "MT_Scalar.h"
|
|
#include "MT_assert.h"
|
|
#include "limits.h"
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Native functions */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
KX_MouseActuator::KX_MouseActuator(
|
|
SCA_IObject* gameobj,
|
|
|
|
KX_KetsjiEngine* ketsjiEngine,
|
|
SCA_MouseManager* eventmgr,
|
|
int acttype,
|
|
bool visible,
|
|
bool* use_axis,
|
|
float* threshold,
|
|
bool* reset,
|
|
int* object_axis,
|
|
bool* local,
|
|
float* sensitivity,
|
|
float* limit_x,
|
|
float* limit_y
|
|
):
|
|
SCA_IActuator(gameobj, KX_ACT_MOUSE),
|
|
m_ketsji(ketsjiEngine),
|
|
m_eventmgr(eventmgr),
|
|
m_type(acttype),
|
|
m_visible(visible),
|
|
m_use_axis_x(use_axis[0]),
|
|
m_use_axis_y(use_axis[1]),
|
|
m_reset_x(reset[0]),
|
|
m_reset_y(reset[1]),
|
|
m_local_x(local[0]),
|
|
m_local_y(local[1])
|
|
{
|
|
m_canvas = m_ketsji->GetCanvas();
|
|
m_oldposition[0] = m_oldposition[1] = -1.f;
|
|
m_limit_x[0] = limit_x[0];
|
|
m_limit_x[1] = limit_x[1];
|
|
m_limit_y[0] = limit_y[0];
|
|
m_limit_y[1] = limit_y[1];
|
|
m_threshold[0] = threshold[0];
|
|
m_threshold[1] = threshold[1];
|
|
m_object_axis[0] = object_axis[0];
|
|
m_object_axis[1] = object_axis[1];
|
|
m_sensitivity[0] = sensitivity[0];
|
|
m_sensitivity[1] = sensitivity[1];
|
|
m_angle[0] = 0.f;
|
|
m_angle[1] = 0.f;
|
|
}
|
|
|
|
KX_MouseActuator::~KX_MouseActuator()
|
|
{
|
|
}
|
|
|
|
bool KX_MouseActuator::Update()
|
|
{
|
|
bool result = false;
|
|
|
|
bool bNegativeEvent = IsNegativeEvent();
|
|
RemoveAllEvents();
|
|
|
|
if (bNegativeEvent)
|
|
return false; // do nothing on negative events
|
|
|
|
KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
|
|
|
|
m_mouse = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice();
|
|
|
|
switch (m_type) {
|
|
case KX_ACT_MOUSE_VISIBILITY:
|
|
{
|
|
if (m_visible) {
|
|
if (m_canvas) {
|
|
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
|
|
}
|
|
}
|
|
else {
|
|
if (m_canvas) {
|
|
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_LOOK:
|
|
{
|
|
if (m_mouse) {
|
|
|
|
float position[2];
|
|
float movement[2];
|
|
MT_Vector3 rotation;
|
|
float setposition[2] = {0.0};
|
|
float center_x = 0.5, center_y = 0.5;
|
|
|
|
getMousePosition(position);
|
|
|
|
movement[0] = position[0];
|
|
movement[1] = position[1];
|
|
|
|
//preventing undesired drifting when resolution is odd
|
|
if ((m_canvas->GetWidth() % 2) != 0) {
|
|
center_x = ((m_canvas->GetWidth() - 1.0) / 2.0) / (m_canvas->GetWidth());
|
|
}
|
|
if ((m_canvas->GetHeight() % 2) != 0) {
|
|
center_y = ((m_canvas->GetHeight() - 1.0) / 2.0) / (m_canvas->GetHeight());
|
|
}
|
|
|
|
//preventing initial skipping.
|
|
if ((m_oldposition[0] <= -0.9) && (m_oldposition[1] <= -0.9)) {
|
|
|
|
if (m_reset_x) {
|
|
m_oldposition[0] = center_x;
|
|
}
|
|
else {
|
|
m_oldposition[0] = position[0];
|
|
}
|
|
|
|
if (m_reset_y) {
|
|
m_oldposition[1] = center_y;
|
|
}
|
|
else {
|
|
m_oldposition[1] = position[1];
|
|
}
|
|
setMousePosition(m_oldposition[0], m_oldposition[1]);
|
|
break;
|
|
}
|
|
|
|
//Calculating X axis.
|
|
if (m_use_axis_x) {
|
|
|
|
if (m_reset_x) {
|
|
setposition[0] = center_x;
|
|
movement[0] -= center_x;
|
|
}
|
|
else {
|
|
setposition[0] = position[0];
|
|
movement[0] -= m_oldposition[0];
|
|
}
|
|
|
|
movement[0] *= -1.0;
|
|
|
|
/* Don't apply the rotation when we are under a certain threshold for mouse
|
|
movement */
|
|
|
|
if (((movement[0] > (m_threshold[0] / 10.0)) ||
|
|
((movement[0] * (-1.0)) > (m_threshold[0] / 10.0)))) {
|
|
|
|
movement[0] *= m_sensitivity[0];
|
|
|
|
if ((m_limit_x[0] != 0.0) && ((m_angle[0] + movement[0]) <= m_limit_x[0])) {
|
|
movement[0] = m_limit_x[0] - m_angle[0];
|
|
}
|
|
|
|
if ((m_limit_x[1] != 0.0) && ((m_angle[0] + movement[0]) >= m_limit_x[1])) {
|
|
movement[0] = m_limit_x[1] - m_angle[0];
|
|
}
|
|
|
|
m_angle[0] += movement[0];
|
|
|
|
switch (m_object_axis[0]) {
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_X:
|
|
{
|
|
rotation = MT_Vector3(movement[0], 0.0, 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
|
|
{
|
|
rotation = MT_Vector3(0.0, movement[0], 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
|
|
{
|
|
rotation = MT_Vector3(0.0, 0.0, movement[0]);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
parent->ApplyRotation(rotation, m_local_x);
|
|
}
|
|
}
|
|
else {
|
|
setposition[0] = center_x;
|
|
}
|
|
|
|
//Calculating Y axis.
|
|
if (m_use_axis_y) {
|
|
|
|
if (m_reset_y) {
|
|
setposition[1] = center_y;
|
|
movement[1] -= center_y;
|
|
}
|
|
else {
|
|
setposition[1] = position[1];
|
|
movement[1] -= m_oldposition[1];
|
|
}
|
|
|
|
movement[1] *= -1.0;
|
|
|
|
/* Don't apply the rotation when we are under a certain threshold for mouse
|
|
movement */
|
|
|
|
if (((movement[1] > (m_threshold[1] / 10.0)) ||
|
|
((movement[1] * (-1.0)) > (m_threshold[1] / 10.0)))) {
|
|
|
|
movement[1] *= m_sensitivity[1];
|
|
|
|
if ((m_limit_y[0] != 0.0) && ((m_angle[1] + movement[1]) <= m_limit_y[0])) {
|
|
movement[1] = m_limit_y[0] - m_angle[1];
|
|
}
|
|
|
|
if ((m_limit_y[1] != 0.0) && ((m_angle[1] + movement[1]) >= m_limit_y[1])) {
|
|
movement[1] = m_limit_y[1] - m_angle[1];
|
|
}
|
|
|
|
m_angle[1] += movement[1];
|
|
|
|
switch (m_object_axis[1])
|
|
{
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_X:
|
|
{
|
|
rotation = MT_Vector3(movement[1], 0.0, 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
|
|
{
|
|
rotation = MT_Vector3(0.0, movement[1], 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
|
|
{
|
|
rotation = MT_Vector3(0.0, 0.0, movement[1]);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
parent->ApplyRotation(rotation, m_local_y);
|
|
}
|
|
}
|
|
else {
|
|
setposition[1] = center_y;
|
|
}
|
|
|
|
setMousePosition(setposition[0], setposition[1]);
|
|
|
|
m_oldposition[0] = position[0];
|
|
m_oldposition[1] = position[1];
|
|
|
|
}
|
|
else {
|
|
//printf("\nNo input device detected for mouse actuator\n");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool KX_MouseActuator::isValid(KX_MouseActuator::KX_ACT_MOUSE_MODE mode)
|
|
{
|
|
return ((mode > KX_ACT_MOUSE_NODEF) && (mode < KX_ACT_MOUSE_MAX));
|
|
}
|
|
|
|
|
|
CValue* KX_MouseActuator::GetReplica()
|
|
{
|
|
KX_MouseActuator* replica = new KX_MouseActuator(*this);
|
|
|
|
replica->ProcessReplica();
|
|
return replica;
|
|
}
|
|
|
|
void KX_MouseActuator::ProcessReplica()
|
|
{
|
|
SCA_IActuator::ProcessReplica();
|
|
}
|
|
|
|
void KX_MouseActuator::getMousePosition(float* pos)
|
|
{
|
|
MT_assert(!m_mouse);
|
|
const SCA_InputEvent & xevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEX);
|
|
const SCA_InputEvent & yevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEY);
|
|
|
|
pos[0] = m_canvas->GetMouseNormalizedX(xevent.m_eventval);
|
|
pos[1] = m_canvas->GetMouseNormalizedY(yevent.m_eventval);
|
|
}
|
|
|
|
void KX_MouseActuator::setMousePosition(float fx, float fy)
|
|
{
|
|
int x, y;
|
|
|
|
x = (int)(fx * m_canvas->GetWidth());
|
|
y = (int)(fy * m_canvas->GetHeight());
|
|
|
|
m_canvas->SetMousePosition(x, y);
|
|
}
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Python functions */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* Integration hooks ------------------------------------------------------- */
|
|
PyTypeObject KX_MouseActuator::Type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"KX_MouseActuator",
|
|
sizeof(PyObjectPlus_Proxy),
|
|
0,
|
|
py_base_dealloc,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
py_base_repr,
|
|
0,0,0,0,0,0,0,0,0,
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
0,0,0,0,0,0,0,
|
|
Methods,
|
|
0,
|
|
0,
|
|
&SCA_IActuator::Type,
|
|
0,0,0,0,0,0,
|
|
py_base_new
|
|
};
|
|
|
|
PyMethodDef KX_MouseActuator::Methods[] = {
|
|
{"reset", (PyCFunction) KX_MouseActuator::sPyReset, METH_NOARGS,"reset() : undo rotation caused by actuator\n"},
|
|
{NULL,NULL} //Sentinel
|
|
};
|
|
|
|
|
|
|
|
PyAttributeDef KX_MouseActuator::Attributes[] = {
|
|
KX_PYATTRIBUTE_BOOL_RW("visible", KX_MouseActuator, m_visible),
|
|
KX_PYATTRIBUTE_BOOL_RW("use_axis_x", KX_MouseActuator, m_use_axis_x),
|
|
KX_PYATTRIBUTE_BOOL_RW("use_axis_y", KX_MouseActuator, m_use_axis_y),
|
|
KX_PYATTRIBUTE_FLOAT_ARRAY_RW("threshold", 0.0, 0.5, KX_MouseActuator, m_threshold, 2),
|
|
KX_PYATTRIBUTE_BOOL_RW("reset_x", KX_MouseActuator, m_reset_x),
|
|
KX_PYATTRIBUTE_BOOL_RW("reset_y", KX_MouseActuator, m_reset_y),
|
|
KX_PYATTRIBUTE_INT_ARRAY_RW("object_axis", 0, 2, 1, KX_MouseActuator, m_object_axis, 2),
|
|
KX_PYATTRIBUTE_BOOL_RW("local_x", KX_MouseActuator, m_local_x),
|
|
KX_PYATTRIBUTE_BOOL_RW("local_y", KX_MouseActuator, m_local_y),
|
|
KX_PYATTRIBUTE_FLOAT_ARRAY_RW("sensitivity", -FLT_MAX, FLT_MAX, KX_MouseActuator, m_sensitivity, 2),
|
|
KX_PYATTRIBUTE_RW_FUNCTION("limit_x", KX_MouseActuator, pyattr_get_limit_x, pyattr_set_limit_x),
|
|
KX_PYATTRIBUTE_RW_FUNCTION("limit_y", KX_MouseActuator, pyattr_get_limit_y, pyattr_set_limit_y),
|
|
KX_PYATTRIBUTE_RW_FUNCTION("angle", KX_MouseActuator, pyattr_get_angle, pyattr_set_angle),
|
|
{ NULL } //Sentinel
|
|
};
|
|
|
|
PyObject* KX_MouseActuator::pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
|
|
{
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
return Py_BuildValue("[f,f]", (self->m_limit_x[0] / M_PI * 180.0), (self->m_limit_x[1] / M_PI * 180.0));
|
|
}
|
|
|
|
int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
|
|
{
|
|
PyObject *item1, *item2;
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
|
|
if (!PyList_Check(value))
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
if (PyList_Size(value) != 2)
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
item1 = PyList_GET_ITEM(value, 0);
|
|
item2 = PyList_GET_ITEM(value, 1);
|
|
|
|
if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
|
|
return PY_SET_ATTR_FAIL;
|
|
}
|
|
else {
|
|
self->m_limit_x[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
|
|
self->m_limit_x[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
|
|
}
|
|
|
|
return PY_SET_ATTR_SUCCESS;
|
|
}
|
|
|
|
PyObject* KX_MouseActuator::pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
|
|
{
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
return Py_BuildValue("[f,f]", (self->m_limit_y[0] / M_PI * 180.0), (self->m_limit_y[1] / M_PI * 180.0));
|
|
}
|
|
|
|
int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
|
|
{
|
|
PyObject *item1, *item2;
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
|
|
if (!PyList_Check(value))
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
if (PyList_Size(value) != 2)
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
item1 = PyList_GET_ITEM(value, 0);
|
|
item2 = PyList_GET_ITEM(value, 1);
|
|
|
|
if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
|
|
return PY_SET_ATTR_FAIL;
|
|
}
|
|
else {
|
|
self->m_limit_y[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
|
|
self->m_limit_y[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
|
|
}
|
|
|
|
return PY_SET_ATTR_SUCCESS;
|
|
}
|
|
|
|
PyObject* KX_MouseActuator::pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
|
|
{
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
return Py_BuildValue("[f,f]", (self->m_angle[0] / M_PI * 180.0), (self->m_angle[1] / M_PI * 180.0));
|
|
}
|
|
|
|
int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
|
|
{
|
|
PyObject *item1, *item2;
|
|
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
|
|
|
|
if (!PyList_Check(value))
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
if (PyList_Size(value) != 2)
|
|
return PY_SET_ATTR_FAIL;
|
|
|
|
item1 = PyList_GET_ITEM(value, 0);
|
|
item2 = PyList_GET_ITEM(value, 1);
|
|
|
|
if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
|
|
return PY_SET_ATTR_FAIL;
|
|
}
|
|
else {
|
|
self->m_angle[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
|
|
self->m_angle[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
|
|
}
|
|
|
|
return PY_SET_ATTR_SUCCESS;
|
|
}
|
|
|
|
PyObject* KX_MouseActuator::PyReset()
|
|
{
|
|
MT_Vector3 rotation;
|
|
KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
|
|
|
|
switch (m_object_axis[0]) {
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_X:
|
|
{
|
|
rotation = MT_Vector3(-1.0 * m_angle[0], 0.0, 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
|
|
{
|
|
rotation = MT_Vector3(0.0, -1.0 * m_angle[0], 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
|
|
{
|
|
rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[0]);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
parent->ApplyRotation(rotation, m_local_x);
|
|
|
|
switch (m_object_axis[1]) {
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_X:
|
|
{
|
|
rotation = MT_Vector3(-1.0 * m_angle[1], 0.0, 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
|
|
{
|
|
rotation = MT_Vector3(0.0, -1.0 * m_angle[1], 0.0);
|
|
break;
|
|
}
|
|
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
|
|
{
|
|
rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[1]);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
parent->ApplyRotation(rotation, m_local_y);
|
|
|
|
m_angle[0] = 0.0;
|
|
m_angle[1] = 0.0;
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
#endif
|