class RControl | .h |
constructor | RControl() |
destructor | ~RControl() |
Update | void Update() |
Flat functions |
if | if(joy==RR_CONTROLLER_MOUSE) qdbg("mouse control Update; button=%d, axis=%d\n",button,axis); #endif if(axis>=0) { // Axis range if(joy==RR_CONTROLLER_MOUSE) { int x,y; app->GetMouseXY(&x,&y); // Scale to -1000..1000 x-=RMGR->resWidth/2; x=x*2000/RMGR->resWidth; //y=RMGR->resHeight-1-y-RMGR->resHeight/2; y-=RMGR->resHeight/2; y=y*2000/RMGR->resHeight; switch(axis) { case AXIS_X: v=x; break; case AXIS_Y: v=y; break; default: v=0; break; } dbg("mouse control Update; v=%d, x=%d,y=%d\n",v,x,y); } else { // Joystick switch(axis) { case AXIS_X: v=joy->x; break; case AXIS_Y: v=joy->y; break; case AXIS_Z: v=joy->z; break; case AXIS_RX: v=joy->rx; break; case AXIS_RY: v=joy->ry; break; case AXIS_RZ: v=joy->rz; break; default: v=0; break; } } // Keep within range if(v<min)v=min; else if(v>max)v=max; // Bring up to 0-base v-=base; if(range!=1000&&range!=0) { // Scale to virtual range (1000) v=v*1000/range; } // Adjust for range //... } else if(button>=0) { // Look at button if(joy==RR_CONTROLLER_MOUSE) { int b=(app->GetMouseButtons()>>1); if(b&(1<<button))v=1000; else v=0; dbg("button %d? b=%d, v=%d\n",button,b,v); } else { // Joystick if(joy->button[button])v=1000; else v=0; } } |
class RControls | .h |
constructor | RControls() |
destructor | ~RControls() |
LoadController | void LoadController(QInfo *info,cstring path,RControl *ctl) Read a controller config from the info file |
LoadConfig | bool LoadConfig(cstring fname) Read controls configuration file 'fname' may be 0, in which case a default controller file is searched for in data/ctrlsets |
Update | void Update() Poll all used controllers; don't use too often please, might be quite slow for old joysticks. |
SetFFSteerResponse | void SetFFSteerResponse(rfloat steeringTorque) Set feedback forces 'steeringTorque' gives the torque that pulls the steering wheel (Nm) |
/*
* RControl
* 05-10-00: Created!
* 19-10-00: Implemented for real and actually using it.
* 18-12-00: Preset files in data/ctrlsets (use Config to set)
* NOTES:
* - Keeps the logic for obtaining controller input, whether from joysticks
* or keyboard
* - Is quite a bit based on the number 1000 (hardcoded ranges).
* (c) Dolphinity/Ruud van Gaal
*/
#include <racer/racer.h>
#include <qlib/debug.h>
#pragma hdrstop
DEBUG_ENABLE
// Default directory for presets
#define CTRLSET_DIR "data/ctrlsets"
// Default preset file (hopefully present in CTRLSET_DIR)
#define DEF_CTRL_FILE "genjoy.ini"
/***********
* RCONTROL *
***********/
RControl::RControl()
{
joy=0;
axis=-1;
button=-1;
min=0; max=1000;
base=0; range=0;
flags=0;
value=0;
}
RControl::~RControl()
{
}
void RControl::Update()
{
int v;
if(!joy)return;
//if(joy==RR_CONTROLLER_MOUSE)return;
#ifdef OBS
if(joy==RR_CONTROLLER_MOUSE)
qdbg("mouse control Update; button=%d, axis=%d\n",button,axis);
#endif
if(axis>=0)
{
// Axis range
if(joy==RR_CONTROLLER_MOUSE)
{
int x,y;
app->GetMouseXY(&x,&y);
// Scale to -1000..1000
x-=RMGR->resWidth/2;
x=x*2000/RMGR->resWidth;
//y=RMGR->resHeight-1-y-RMGR->resHeight/2;
y-=RMGR->resHeight/2;
y=y*2000/RMGR->resHeight;
switch(axis)
{
case AXIS_X: v=x; break;
case AXIS_Y: v=y; break;
default: v=0; break;
}
//qdbg("mouse control Update; v=%d, x=%d,y=%d\n",v,x,y);
} else
{
// Joystick
switch(axis)
{
case AXIS_X: v=joy->x; break;
case AXIS_Y: v=joy->y; break;
case AXIS_Z: v=joy->z; break;
case AXIS_RX: v=joy->rx; break;
case AXIS_RY: v=joy->ry; break;
case AXIS_RZ: v=joy->rz; break;
default: v=0; break;
}
}
// Keep within range
if(v<min)v=min;
else if(v>max)v=max;
// Bring up to 0-base
v-=base;
if(range!=1000&&range!=0)
{
// Scale to virtual range (1000)
v=v*1000/range;
}
// Adjust for range
//...
} else if(button>=0)
{
// Look at button
if(joy==RR_CONTROLLER_MOUSE)
{
int b=(app->GetMouseButtons()>>1);
if(b&(1<<button))v=1000;
else v=0;
//qdbg("button %d? b=%d, v=%d\n",button,b,v);
} else
{
// Joystick
if(joy->button[button])v=1000;
else v=0;
}
}
// Negation
if(flags&RControl::NEGATE)v=1000-v;
// Store value
value=v;
}
/************
* RCONTROLS *
************/
RControls::RControls()
{
int i;
joys=0;
for(i=0;i<MAX_CONTROLLER_TYPE;i++)
control[i]=0;
for(i=0;i<MAX_CONTROLLER;i++)
{
fxAlign[i]=fxFriction[i]=fxInertia[i]=0;
flags[i]=0;
ffMaxTorque[i]=ffMaxForce[i]=ffDelay[i]=0;
}
}
RControls::~RControls()
{
int i;
// Delete all effects
for(i=0;i<MAX_CONTROLLER;i++)
{
if(fxAlign[i])delete fxAlign[i];
if(fxFriction[i])delete fxFriction[i];
if(fxInertia[i])delete fxInertia[i];
}
for(i=0;i<joys;i++)
{
if(joy[i]!=0&&joy[i]!=RR_CONTROLLER_MOUSE)delete joy[i];
}
}
void RControls::LoadController(QInfo *info,cstring path,RControl *ctl)
// Read a controller config from the info file
{
char buf[256];
int index;
qstring s;
// Get controller or notice if none is used for this control
// (may be keyboard still)
sprintf(buf,"%s.controller",path);
index=info->GetInt(buf);
if(index<0)
{ ctl->joy=0;
goto no_ctl;
} else
{ if(index>joys-1)index=joys-1;
ctl->joy=joy[index];
}
// Axis
sprintf(buf,"%s.axis",path);
info->GetString(buf,s);
if(s=="x")ctl->axis=RControl::AXIS_X;
else if(s=="y")ctl->axis=RControl::AXIS_Y;
else if(s=="z")ctl->axis=RControl::AXIS_Z;
else if(s=="rx")ctl->axis=RControl::AXIS_RX;
else if(s=="ry")ctl->axis=RControl::AXIS_RY;
else if(s=="rz")ctl->axis=RControl::AXIS_RZ;
else
{ //qwarn("Unknown controller axis type for '%s'",buf);
ctl->axis=RControl::AXIS_NONE;
}
// Axis range
int min,max;
sprintf(buf,"%s.min",path);
min=info->GetInt(buf,0);
sprintf(buf,"%s.max",path);
max=info->GetInt(buf,1000);
// Calculate base axis value and range
if(min<max)
{
ctl->base=min;
ctl->range=max-min;
ctl->flags&=~RControl::NEGATE;
} else
{
int t;
ctl->base=max;
ctl->range=min-max;
ctl->flags|=RControl::NEGATE;
// Swap min/max
t=min;
min=max;
max=t;
}
ctl->min=min;
ctl->max=max;
/*qdbg("RControls:LoadController: min=%d, max=%d, base=%d,"
" range=%d, flags=%d\n",
ctl->min,ctl->max,ctl->base,ctl->range,ctl->flags);*/
// Button?
int button;
sprintf(buf,"%s.button",path);
button=info->GetInt(buf,-1);
ctl->button=button;
// Take precedence over axis if a button is specified
if(ctl->button!=-1)
ctl->axis=RControl::AXIS_NONE;
//qdbg("ctl->button=%d\n",button);
// Manual negate?
sprintf(buf,"%s.negate",path);
if(info->GetInt(buf))
ctl->flags|=RControl::NEGATE;
no_ctl:;
// Check for keys...
}
bool RControls::LoadConfig(cstring fname)
// Read controls configuration file
// 'fname' may be 0, in which case a default controller file is searched for
// in data/ctrlsets
{
QInfo *info;
int i;
char buf[256];
if(!fname)
{
// Search for selected controller file
RMGR->GetMainInfo()->GetString("ini.controls",buf,DEF_CTRL_FILE);
qdbg("RControls: indirection to '%s'\n",buf);
info=new QInfo(RFindFile(buf,CTRLSET_DIR));
} else
{
// Explicit controller file
qwarn("RControls: explicit controller file given; this is obsolete");
info=new QInfo(RFindFile(fname));
}
joys=info->GetInt("controllers.count");
// Only 1 support currently (QDXJoy)
if(joys>1)
{
qwarn("Current limit of controllers is just 1 (more specified in %s)",
fname);
joys=1;
}
if(joys>MAX_CONTROLLER)
{ qwarn("Too many controllers (max=4) specified in controller file (%s)",
fname);
joys=MAX_CONTROLLER;
}
// Open all used controllers
for(i=0;i<joys;i++)
{
int index;
// Check for special controllers, like the mouse or keyboard
sprintf(buf,"controllers.controller%d.mouse",i);
if(info->GetInt(buf))
{
joy[i]=RR_CONTROLLER_MOUSE;
} else
{
// Game controller
sprintf(buf,"controllers.controller%d.index",i);
index=info->GetInt(buf);
// Flags
sprintf(buf,"controllers.controller%d.force_feedback",i);
if(info->GetInt(buf))
{
flags[i]|=FORCE_FEEDBACK;
// Get FF settings
sprintf(buf,"controllers.controller%d.max_torque",i);
ffMaxTorque[i]=info->GetInt(buf);
sprintf(buf,"controllers.controller%d.max_force",i);
ffMaxForce[i]=info->GetInt(buf);
sprintf(buf,"controllers.controller%d.delay",i);
ffDelay[i]=info->GetInt(buf);
}
// Open joystick
joy[i]=new QDXJoy(index);
if(!joy[i]->Open())
{ qerr("Can't open controller %d (gamecontroller index %d)",i,index);
}
}
}
// Read all controls
cstring ctlName[]=
{ "steerleft","steerright","throttle","brakes","shiftup","shiftdown",
"clutch"
};
for(i=0;i<MAX_CONTROLLER_TYPE;i++)
{
control[i]=new RControl();
if(!control[i])break;
sprintf(buf,"controls.%s",ctlName[i]);
LoadController(info,buf,control[i]);
}
// Acquire all controllers
for(i=0;i<joys;i++)
{
// Open only real game controllers
if(joy[i]==RR_CONTROLLER_MOUSE)continue;
if(flags[i]&FORCE_FEEDBACK)
{
if(!joy[i]->IsForceFeedback())
{
qwarn("Controller %d can't do force feedback; disabling FF",i);
flags[i]&=~FORCE_FEEDBACK;
} else
{
// Use the force, Luke!
// Disable autocentering BEFORE acquiring device (!)
joy[i]->DisableAutoCenter();
fxAlign[i]=new QDXFFEffect(joy[i]);
fxAlign[i]->SetupConstantForce();
//fxAlign[i]->Start();
}
}
joy[i]->Acquire();
}
return TRUE;
}
void RControls::Update()
// Poll all used controllers; don't use too often please,
// might be quite slow for old joysticks.
{
int i;
for(i=0;i<joys;i++)
{
if(joy[i]!=0&&joy[i]!=RR_CONTROLLER_MOUSE&&joy[i]->IsOpen())
{
joy[i]->Poll();
}
}
for(i=0;i<MAX_CONTROLLER_TYPE;i++)
{
control[i]->Update();
}
}
/*****************
* FORCE FEEDBACK *
*****************/
void RControls::SetFFSteerResponse(rfloat steeringTorque)
// Set feedback forces
// 'steeringTorque' gives the torque that pulls the steering wheel (Nm)
{
int i;
rfloat fx,fy;
// Calculate steering force from torque
// Find FF controllers
for(i=0;i<joys;i++)
{
if(!(flags[i]&FORCE_FEEDBACK))continue;
// Check for force to be valid
if(!ffMaxTorque[i])continue;
fx=steeringTorque*ffMaxForce[i]/ffMaxTorque[i];
if(fx<-ffMaxForce[i])fx=-ffMaxForce[i];
else if(fx>ffMaxForce[i])fx=ffMaxForce[i];
fy=0;
//qdbg("RControls::SetFFResponse(); fx=%f, fy=%f\n",fx,fy);
// Update the aligning effect
fxAlign[i]->UpdateConstantForce(fx,fy);
}
}