* Example program for the Allegro library, by Beoran.
*
* Exhaustive haptics example.
*/
#include <string>
#define ALLEGRO_UNSTABLE
#include "allegro5/allegro.h"
#include "allegro5/allegro_font.h"
#include "allegro5/allegro_primitives.h"
#include "allegro5/allegro_ttf.h"
#include "nihgui.hpp"
#include "common.c"
struct Haptic
{
ALLEGRO_HAPTIC *haptic;
ALLEGRO_HAPTIC_EFFECT effect;
ALLEGRO_HAPTIC_EFFECT_ID id;
const char *name;
bool playing;
};
#define EX_MAX_HAPTICS 8
static Haptic haptics[EX_MAX_HAPTICS];
static int num_haptics = 0;
static ALLEGRO_EVENT_QUEUE * joystick_queue;
static ALLEGRO_TIMER * update_timer = NULL;
static void release_all_haptics() {
for (int i = 0; i < num_haptics; i++) {
al_release_haptic(haptics[i].haptic);
haptics[i].haptic = NULL;
}
}
static void get_all_haptics() {
num_haptics = 0;
ALLEGRO_DISPLAY * display = al_get_current_display();
if (al_is_display_haptic(display)) {
haptics[num_haptics].haptic = al_get_haptic_from_display(display);
if (haptics[num_haptics].haptic) {
haptics[num_haptics].name = (const char *)"display";
haptics[num_haptics].playing = false;
num_haptics++;
}
}
for (int i = 0;
num_haptics < EX_MAX_HAPTICS && i < al_get_num_joysticks();
i++)
{
ALLEGRO_JOYSTICK *joy = al_get_joystick(i);
if (al_is_joystick_haptic(joy)) {
haptics[num_haptics].haptic = al_get_haptic_from_joystick(joy);
if (haptics[num_haptics].haptic) {
const char *name = al_get_joystick_name(joy);
haptics[num_haptics].name = (const char *)name;
haptics[num_haptics].playing = false;
num_haptics++;
}
}
}
}
struct CapacityName
{
int value;
const char *name;
};
static const CapacityName capname[] =
{
{ALLEGRO_HAPTIC_RUMBLE, "ALLEGRO_HAPTIC_RUMBLE"},
{ALLEGRO_HAPTIC_PERIODIC, "ALLEGRO_HAPTIC_PERIODIC"},
{ALLEGRO_HAPTIC_CONSTANT, "ALLEGRO_HAPTIC_CONSTANT"},
{ALLEGRO_HAPTIC_SPRING, "ALLEGRO_HAPTIC_SPRING"},
{ALLEGRO_HAPTIC_FRICTION, "ALLEGRO_HAPTIC_FRICTION"},
{ALLEGRO_HAPTIC_DAMPER, "ALLEGRO_HAPTIC_DAMPER"},
{ALLEGRO_HAPTIC_INERTIA, "ALLEGRO_HAPTIC_INERTIA"},
{ALLEGRO_HAPTIC_RAMP, "ALLEGRO_HAPTIC_RAMP"},
{ALLEGRO_HAPTIC_SQUARE, "ALLEGRO_HAPTIC_SQUARE"},
{ALLEGRO_HAPTIC_TRIANGLE, "ALLEGRO_HAPTIC_TRIANGLE"},
{ALLEGRO_HAPTIC_SINE, "ALLEGRO_HAPTIC_SINE"},
{ALLEGRO_HAPTIC_SAW_UP, "ALLEGRO_HAPTIC_SAW_UP"},
{ALLEGRO_HAPTIC_SAW_DOWN, "ALLEGRO_HAPTIC_SAW_DOWN"},
{ALLEGRO_HAPTIC_CUSTOM, "ALLEGRO_HAPTIC_CUSTOM"},
{ALLEGRO_HAPTIC_GAIN, "ALLEGRO_HAPTIC_GAIN"},
{ALLEGRO_HAPTIC_ANGLE, "ALLEGRO_HAPTIC_ANGLE"},
{ALLEGRO_HAPTIC_RADIUS, "ALLEGRO_HAPTIC_RADIUS"},
{ALLEGRO_HAPTIC_AZIMUTH, "ALLEGRO_HAPTIC_AZIMUTH"}
};
#define EX_START_TYPES 0
#define EX_MAX_TYPES 8
#define EX_END_TYPES 8
#define EX_START_WAVES 8
#define EX_END_WAVES 13
#define EX_MAX_WAVES 5
#define EX_START_COORDS 15
#define EX_MAX_COORDS 3
#define EX_END_COORDS 18
class CanStopAndPlay
{
public:
virtual void on_play() = 0;
virtual void on_stop() = 0;
};
class PlayButton: public Button
{
protected:
CanStopAndPlay *stop_and_play;
public:
PlayButton(CanStopAndPlay *snp) :
Button("Play"),
stop_and_play(snp)
{
}
void on_click(int mx, int my);
};
void PlayButton::on_click(int, int)
{
if (is_disabled())
return;
log_printf("Start playing...\n");
if (stop_and_play) {
stop_and_play->on_play();
}
}
class StopButton: public Button
{
protected:
CanStopAndPlay *stop_and_play;
public:
StopButton(CanStopAndPlay *snp) :
Button("Stop"),
stop_and_play(snp)
{
}
void on_click(int mx, int my);
};
void StopButton::on_click(int, int)
{
if (is_disabled())
return;
log_printf("Stop playing...\n");
if (stop_and_play) {
stop_and_play->on_stop();
}
}
class Prog: public CanStopAndPlay
{
private:
Dialog d;
List device_list;
List type_list;
List waveform_list;
Label device_label;
Label type_label;
Label waveform_label;
HSlider length_slider;
HSlider delay_slider;
HSlider loops_slider;
Label replay_label;
Label length_label;
Label delay_label;
Label loops_label;
HSlider attack_length_slider;
HSlider attack_level_slider;
HSlider fade_length_slider;
HSlider fade_level_slider;
Label envelope_label;
Label attack_length_label;
Label attack_level_label;
Label fade_length_label;
Label fade_level_label;
HSlider angle_slider;
HSlider radius_slider;
HSlider azimuth_slider;
Label coordinates_label;
Label angle_label;
Label radius_label;
Label azimuth_label;
HSlider level_slider;
Label constant_effect_label;
Label level_label;
HSlider start_level_slider;
HSlider end_level_slider;
Label ramp_effect_label;
Label start_level_label;
Label end_level_label;
HSlider right_saturation_slider;
HSlider right_coeff_slider;
HSlider left_saturation_slider;
HSlider left_coeff_slider;
HSlider deadband_slider;
HSlider center_slider;
Label right_saturation_label;
Label right_coeff_label;
Label left_saturation_label;
Label left_coeff_label;
Label condition_effect_label;
Label deadband_label;
Label center_label;
HSlider period_slider;
HSlider magnitude_slider;
HSlider offset_slider;
HSlider phase_slider;
Label periodic_effect_label;
Label period_label;
Label magnitude_label;
Label offset_label;
Label phase_label;
HSlider strong_magnitude_slider;
HSlider weak_magnitude_slider;
Label rumble_effect_label;
Label strong_magnitude_label;
Label weak_magnitude_label;
HSlider gain_slider;
Label gain_label;
HSlider autocenter_slider;
Label autocenter_label;
Label message_label;
Label message_label_label;
PlayButton play_button;
StopButton stop_button;
Haptic *last_haptic;
Haptic *show_haptic;
public:
Prog(const Theme & theme, ALLEGRO_DISPLAY *display);
void run();
void update();
void update_controls(Haptic *dev);
virtual void on_play();
virtual void on_stop();
void get_envelope(ALLEGRO_HAPTIC_ENVELOPE *envelope);
};
Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
d(Dialog(theme, display, 20, 40)),
device_list(0),
type_list(0),
waveform_list(0),
device_label("Haptic Device"),
type_label("Haptic Effect Type"),
waveform_label("Wave Form Periodic Effect"),
length_slider(1, 10),
delay_slider(1, 10),
loops_slider(1, 10),
replay_label("Replay"),
length_label("Length", false),
delay_label("Delay", false),
loops_label("Loops"),
attack_length_slider(2, 10),
attack_level_slider(4, 10),
fade_length_slider(2, 10),
fade_level_slider(4, 10),
envelope_label("Envelope"),
attack_length_label("Attack Length", false),
attack_level_label("Attack Level", false),
fade_length_label("Fade Length", false),
fade_level_label("Fade Level", false),
angle_slider(0, 360),
radius_slider(0, 10),
azimuth_slider(180, 360),
coordinates_label("Coordinates"),
angle_label("Angle", false),
radius_label("Radius", false),
azimuth_label("Azimuth", false),
level_slider(5, 10),
constant_effect_label("Constant Effect"),
level_label("Level", false),
start_level_slider(3, 10),
end_level_slider(7, 10),
ramp_effect_label("Ramp Effect"),
start_level_label("Start Level", false),
end_level_label("End Level", false),
right_saturation_slider(5, 10),
right_coeff_slider(5, 10),
left_saturation_slider(5, 10),
left_coeff_slider(5, 10),
deadband_slider(1, 10),
center_slider(5, 10),
right_saturation_label("Right Saturation", false),
right_coeff_label("Right Coefficient", false),
left_saturation_label("Left Saturation", false),
left_coeff_label("Left Coefficient", false),
condition_effect_label("Condition Effect"),
deadband_label("Deadband", false),
center_label("Center", false),
period_slider(1, 10),
magnitude_slider(5, 10),
offset_slider(0, 10),
phase_slider(0, 10),
periodic_effect_label("Periodic Effect"),
period_label("Period", false),
magnitude_label("Magnitude", false),
offset_label("Offset", false),
phase_label("Phase", false),
strong_magnitude_slider(5, 10),
weak_magnitude_slider(5, 10),
rumble_effect_label("Rumble effect"),
strong_magnitude_label("Strong Magnitude", false),
weak_magnitude_label("Weak Magnitude", false),
gain_slider(10, 10),
gain_label("Gain"),
autocenter_slider(0, 10),
autocenter_label("Autocenter"),
message_label("Ready.", false),
message_label_label("Status", false),
play_button(this),
stop_button(this),
last_haptic(NULL),
show_haptic(NULL)
{
for (int i = 0; i < num_haptics; i++) {
device_list.append_item(haptics[i].name);
}
d.add(device_label, 0, 1, 7, 1);
d.add(device_list, 0, 2, 7, 8);
for (int i = EX_START_TYPES; i < EX_END_TYPES; i++) {
type_list.append_item(capname[i].name);
}
d.add(type_label, 7, 1, 6, 1);
d.add(type_list, 7, 2, 6, 8);
for (int i = EX_START_WAVES; i < EX_END_WAVES; i++) {
waveform_list.append_item(capname[i].name);
}
d.add(waveform_label, 13, 1, 7, 1);
d.add(waveform_list, 13, 2, 7, 8);
d.add(replay_label, 0, 11, 7, 1);
d.add(length_label, 0, 12, 2, 1);
d.add(length_slider, 2, 12, 5, 1);
d.add(delay_label, 0, 13, 2, 1);
d.add(delay_slider, 2, 13, 5, 1);
d.add(loops_label, 7, 11, 7, 1);
d.add(loops_slider, 7, 12, 6, 1);
d.add(gain_label, 13, 11, 7, 1);
d.add(gain_slider, 13, 12, 7, 1);
d.add(autocenter_label, 13, 13, 7, 1);
d.add(autocenter_slider, 13, 14, 7, 1);
d.add(envelope_label, 0, 15, 9, 1);
d.add(attack_length_label, 0, 16, 3, 1);
d.add(attack_length_slider, 4, 16, 6, 1);
d.add(attack_level_label, 0, 17, 3, 1);
d.add(attack_level_slider, 4, 17, 6, 1);
d.add(fade_length_label, 0, 18, 3, 1);
d.add(fade_length_slider, 4, 18, 6, 1);
d.add(fade_level_label, 0, 19, 3, 1);
d.add(fade_level_slider, 4, 19, 6, 1);
d.add(coordinates_label, 11, 15, 9, 1);
d.add(angle_label, 11, 16, 2, 1);
d.add(angle_slider, 13, 16, 7, 1);
d.add(radius_label, 11, 17, 2, 1);
d.add(radius_slider, 13, 17, 7, 1);
d.add(azimuth_label, 11, 18, 2, 1);
d.add(azimuth_slider, 13, 18, 7, 1);
d.add(condition_effect_label, 0, 21, 9, 1);
d.add(right_coeff_label, 0, 22, 4, 1);
d.add(right_coeff_slider, 4, 22, 6, 1);
d.add(right_saturation_label, 0, 23, 4, 1);
d.add(right_saturation_slider, 4, 23, 6, 1);
d.add(left_coeff_label, 0, 24, 4, 1);
d.add(left_coeff_slider, 4, 24, 6, 1);
d.add(left_saturation_label, 0, 25, 4, 1);
d.add(left_saturation_slider, 4, 25, 6, 1);
d.add(deadband_label, 0, 26, 4, 1);
d.add(deadband_slider, 4, 26, 6, 1);
d.add(center_label, 0, 27, 4, 1);
d.add(center_slider, 4, 27, 6, 1);
d.add(periodic_effect_label, 11, 21, 9, 1);
d.add(period_label, 11, 22, 2, 1);
d.add(period_slider, 13, 22, 7, 1);
d.add(magnitude_label, 11, 23, 2, 1);
d.add(magnitude_slider, 13, 23, 7, 1);
d.add(offset_label, 11, 24, 2, 1);
d.add(offset_slider, 13, 24, 7, 1);
d.add(phase_label, 11, 25, 2, 1);
d.add(phase_slider, 13, 25, 7, 1);
d.add(ramp_effect_label, 11, 29, 9, 1);
d.add(start_level_label, 11, 30, 2, 1);
d.add(start_level_slider, 13, 30, 7, 1);
d.add(end_level_label, 11, 31, 2, 1);
d.add(end_level_slider, 13, 31, 7, 1);
d.add(rumble_effect_label, 0, 29, 9, 1);
d.add(strong_magnitude_label, 0, 30, 4, 1);
d.add(strong_magnitude_slider, 4, 30, 6, 1);
d.add(weak_magnitude_label, 0, 31, 4, 1);
d.add(weak_magnitude_slider, 4, 31, 6, 1);
d.add(constant_effect_label, 0, 33, 9, 1);
d.add(level_label, 0, 34, 3, 1);
d.add(level_slider, 4, 34, 6, 1);
d.add(message_label_label, 0, 36, 2, 1);
d.add(message_label, 2, 36, 12, 1);
d.add(play_button, 6, 38, 3, 2);
d.add(stop_button, 12, 38, 3, 2);
d.register_event_source(al_get_timer_event_source(update_timer));
}
void Prog::update()
{
if (last_haptic && last_haptic->playing) {
if (!al_is_haptic_effect_playing(&last_haptic->id)) {
last_haptic->playing = false;
al_release_haptic_effect(&last_haptic->id);
message_label.set_text("Done.");
play_button.set_disabled(false);
d.request_draw();
log_printf("Play done on %s\n", last_haptic->name);
}
}
ALLEGRO_EVENT e;
while(al_get_next_event(joystick_queue, &e)) {
if (e.type == ALLEGRO_EVENT_JOYSTICK_CONFIGURATION) {
al_reconfigure_joysticks();
release_all_haptics();
get_all_haptics();
device_list.clear_items();
for (int i = 0; i < num_haptics; i++) {
device_list.append_item(haptics[i].name);
}
log_printf("Hot plugging detected...\n");
message_label.set_text("Hot Plugging...");
play_button.set_disabled(false);
d.request_draw();
}
}
int devno = device_list.get_cur_value();
Haptic *dev = haptics + devno;
if (dev && dev->haptic) {
if (dev != show_haptic) {
play_button.set_disabled(false);
update_controls(dev);
show_haptic = dev;
message_label.set_text("Haptic Device Found.");
d.request_draw();
}
} else {
play_button.set_disabled(true);
message_label.set_text("No Haptic Device.");
d.request_draw();
}
}
void Prog::run()
{
d.prepare();
while (!d.is_quit_requested()) {
update();
if (d.is_draw_requested()) {
al_clear_to_color(al_map_rgb(128, 148, 168));
d.draw();
al_flip_display();
}
d.run_step(true);
}
on_stop();
}
#define TEST_CAP(CAP, FLAG) (((CAP) & (FLAG)) == (FLAG))
void Prog::update_controls(Haptic *dev)
{
bool condition, envelope, periodic;
int cap = 0;
if (dev) {
cap = al_get_haptic_capabilities(dev->haptic);
}
gain_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
gain_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
autocenter_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AUTOCENTER));
autocenter_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AUTOCENTER));
envelope = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC) ||
TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT) ||
TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP);
envelope_label.set_disabled(!envelope);
attack_level_slider.set_disabled(!envelope);
attack_length_slider.set_disabled(!envelope);
fade_level_slider.set_disabled(!envelope);
fade_length_slider.set_disabled(!envelope);
attack_level_label.set_disabled(!envelope);
attack_length_label.set_disabled(!envelope);
fade_level_label.set_disabled(!envelope);
fade_length_label.set_disabled(!envelope);
angle_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
angle_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
radius_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
radius_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
azimuth_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));
azimuth_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));
condition = TEST_CAP(cap, ALLEGRO_HAPTIC_DAMPER) ||
TEST_CAP(cap, ALLEGRO_HAPTIC_FRICTION) ||
TEST_CAP(cap, ALLEGRO_HAPTIC_INERTIA) ||
TEST_CAP(cap, ALLEGRO_HAPTIC_SPRING);
condition_effect_label.set_disabled(!condition);
right_coeff_slider.set_disabled(!condition);
left_coeff_slider.set_disabled(!condition);
right_saturation_slider.set_disabled(!condition);
left_saturation_slider.set_disabled(!condition);
center_slider.set_disabled(!condition);
deadband_slider.set_disabled(!condition);
right_coeff_label.set_disabled(!condition);
left_coeff_label.set_disabled(!condition);
right_saturation_label.set_disabled(!condition);
left_saturation_label.set_disabled(!condition);
center_label.set_disabled(!condition);
deadband_label.set_disabled(!condition);
constant_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
ramp_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
start_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
start_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
end_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
end_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
periodic = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC);
waveform_label.set_disabled(!periodic);
waveform_list.set_disabled(!periodic);
periodic_effect_label.set_disabled(!periodic);
period_slider.set_disabled(!periodic);
magnitude_slider.set_disabled(!periodic);
offset_slider.set_disabled(!periodic);
phase_slider.set_disabled(!periodic);
period_label.set_disabled(!periodic);
magnitude_label.set_disabled(!periodic);
offset_label.set_disabled(!periodic);
phase_label.set_disabled(!periodic);
type_list.clear_items();
for (int i = EX_START_TYPES; i < EX_END_TYPES; i++) {
const CapacityName *cn = &capname[i];
if (TEST_CAP(cap, cn->value)) {
type_list.append_item(cn->name);
}
}
waveform_list.clear_items();
for (int i = EX_START_WAVES; i < EX_END_WAVES; i++) {
const CapacityName *cn = &capname[i];
if (TEST_CAP(cap, cn->value)) {
waveform_list.append_item(cn->name);
}
}
}
static int name_to_cap(const std::string & name)
{
for (int i = 0; i < EX_END_WAVES; i++) {
if (name == capname[i].name) {
return capname[i].value;
}
}
return -1;
}
static const char *cap_to_name(int cap)
{
for (int i = 0; i < EX_END_WAVES; i++) {
if (cap == capname[i].value) {
return capname[i].name;
}
}
return "unknown";
}
static double slider_to_magnitude(const HSlider & slider)
{
double value = (double)slider.get_cur_value();
double max = (double)slider.get_max_value();
return value / max;
}
static double slider_to_duration(const HSlider & slider)
{
double value = (double)slider.get_cur_value();
double max = 1.0;
return value / max;
}
static double slider_to_angle(const HSlider & slider)
{
double value = (double)slider.get_cur_value();
double max = (double)slider.get_max_value();
return value / max;
}
void Prog::get_envelope(ALLEGRO_HAPTIC_ENVELOPE *envelope)
{
if (!envelope)
return;
envelope->attack_length = slider_to_duration(attack_length_slider);
envelope->fade_length = slider_to_duration(fade_length_slider);
envelope->attack_level = slider_to_magnitude(attack_level_slider);
envelope->fade_level = slider_to_magnitude(fade_level_slider);
}
void Prog::on_play()
{
int devno = device_list.get_cur_value();
if (devno < 0 || devno >= num_haptics) {
message_label.set_text("No Haptic Device!");
log_printf("No such device: %d\n", devno);
return;
}
Haptic *haptic = haptics + devno;
if (!haptic || !haptic->haptic) {
log_printf("Device is NULL: %d\n", devno);
message_label.set_text("Device Is NULL!");
return;
}
if (!al_is_haptic_active(haptic->haptic)) {
message_label.set_text("Device Not Active!");
log_printf("Device is not active: %d\n", devno);
return;
}
if (haptic->playing) {
al_stop_haptic_effect(&haptic->id);
haptic->playing = false;
al_release_haptic_effect(&haptic->id);
}
double gain = slider_to_magnitude(gain_slider);
al_set_haptic_gain(haptic->haptic, gain);
double autocenter = slider_to_magnitude(autocenter_slider);
al_set_haptic_autocenter(haptic->haptic, autocenter);
int type = name_to_cap(type_list.get_selected_item_text());
int wavetype = name_to_cap(waveform_list.get_selected_item_text());
if (type < 0) {
message_label.set_text("Unknown Effect Type!");
log_printf("Unknown effect type: %d on %s\n", type, haptic->name);
return;
}
if ((wavetype < 0) && (type == ALLEGRO_HAPTIC_PERIODIC)) {
message_label.set_text("Unknown Wave Form!");
log_printf("Unknown wave type: %d on %s\n", wavetype, haptic->name);
return;
}
haptic->effect.type = type;
haptic->effect.replay.delay = slider_to_duration(delay_slider);
haptic->effect.replay.length = slider_to_duration(length_slider);
int loops = loops_slider.get_cur_value();
haptic->effect.direction.angle = slider_to_angle(angle_slider);
haptic->effect.direction.radius = slider_to_magnitude(angle_slider);
haptic->effect.direction.azimuth = slider_to_angle(angle_slider);
switch (type) {
case ALLEGRO_HAPTIC_RUMBLE:
haptic->effect.data.rumble.strong_magnitude = slider_to_magnitude(strong_magnitude_slider);
haptic->effect.data.rumble.weak_magnitude = slider_to_magnitude(weak_magnitude_slider);
break;
case ALLEGRO_HAPTIC_PERIODIC:
get_envelope(&haptic->effect.data.periodic.envelope);
haptic->effect.data.periodic.waveform = wavetype;
haptic->effect.data.periodic.magnitude = slider_to_magnitude(magnitude_slider);
haptic->effect.data.periodic.period = slider_to_duration(period_slider);
haptic->effect.data.periodic.offset = slider_to_duration(offset_slider);
haptic->effect.data.periodic.phase = slider_to_duration(phase_slider);
haptic->effect.data.periodic.custom_len = 0;
haptic->effect.data.periodic.custom_data = NULL;
break;
case ALLEGRO_HAPTIC_CONSTANT:
get_envelope(&haptic->effect.data.constant.envelope);
haptic->effect.data.constant.level = slider_to_magnitude(level_slider);
break;
case ALLEGRO_HAPTIC_RAMP:
get_envelope(&haptic->effect.data.ramp.envelope);
haptic->effect.data.ramp.start_level = slider_to_magnitude(start_level_slider);
haptic->effect.data.ramp.end_level = slider_to_magnitude(end_level_slider);
break;
case ALLEGRO_HAPTIC_SPRING:
case ALLEGRO_HAPTIC_FRICTION:
case ALLEGRO_HAPTIC_DAMPER:
case ALLEGRO_HAPTIC_INERTIA:
haptic->effect.data.condition.right_saturation = slider_to_magnitude(right_saturation_slider);
haptic->effect.data.condition.left_saturation = slider_to_magnitude(left_saturation_slider);
haptic->effect.data.condition.right_coeff = slider_to_magnitude(right_coeff_slider);
haptic->effect.data.condition.left_coeff = slider_to_magnitude(left_coeff_slider);
haptic->effect.data.condition.deadband = slider_to_magnitude(deadband_slider);
haptic->effect.data.condition.center = slider_to_magnitude(center_slider);
* controller that supports condition effects anyway... :p
*/
break;
default:
message_label.set_text("Unknown Effect Type!");
log_printf("Unknown effect type %d %d\n", devno, type);
return;
}
if (!al_is_haptic_effect_ok(haptic->haptic, &haptic->effect)) {
message_label.set_text("Effect Not Supported!");
log_printf("Playing of effect type %s on %s not supported\n",
cap_to_name(type), haptic->name);
return;
}
haptic->playing = al_upload_and_play_haptic_effect(haptic->haptic,
&haptic->effect, &haptic->id, loops);
if (haptic->playing) {
message_label.set_text("Playing...");
log_printf("Started playing %d loops of effect type %s on %s\n",
loops, cap_to_name(type), haptic->name);
last_haptic = haptic;
}
else {
message_label.set_text("Playing of effect failed!");
log_printf("Playing of effect type %s on %s failed\n", cap_to_name(type),
haptic->name);
}
play_button.set_disabled(true);
}
void Prog::on_stop()
{
int devno = device_list.get_cur_value();
if (devno < 0 || devno >= num_haptics) {
log_printf("No such device %d\n", devno);
return;
}
Haptic *haptic = haptics + devno;
if (haptic->playing && al_is_haptic_effect_playing(&haptic->id)) {
al_stop_haptic_effect(&haptic->id);
haptic->playing = false;
al_release_haptic_effect(&haptic->id);
log_printf("Stopped device %d: %s\n", devno, haptic->name);
}
message_label.set_text("Stopped.");
play_button.set_disabled(false);
}
int main(int argc, char *argv[])
{
ALLEGRO_DISPLAY *display;
ALLEGRO_FONT *font;
(void)argc;
(void)argv;
if (!al_init()) {
abort_example("Could not init Allegro\n");
}
al_init_primitives_addon();
al_install_keyboard();
al_install_mouse();
al_install_joystick();
if (!al_install_haptic()) {
abort_example("Could not init haptics\n");
}
al_init_font_addon();
al_init_ttf_addon();
al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS);
display = al_create_display(800, 600);
if (!display) {
abort_example("Unable to create display\n");
}
open_log();
font = al_load_font("data/DejaVuSans.ttf", 11, 0);
if (!font) {
log_printf("Failed to load data/DejaVuSans.ttf\n");
font = al_create_builtin_font();
if (!font) {
abort_example("Could not create builtin font.\n");
}
}
joystick_queue = al_create_event_queue();
if (!joystick_queue) {
abort_example("Could not create joystick event queue font.\n");
}
al_register_event_source(joystick_queue, al_get_joystick_event_source());
get_all_haptics();
{
update_timer = al_create_timer(1.0);
Theme theme(font);
Prog prog(theme, display);
al_start_timer(update_timer);
prog.run();
al_destroy_timer(update_timer);
}
release_all_haptics();
al_destroy_event_queue(joystick_queue);
close_log(false);
al_destroy_font(font);
return 0;
}