Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
109 KB
Referenced Files
None
Subscribers
None
diff --git a/include/r-tech1/input/input-manager.h b/include/r-tech1/input/input-manager.h
index a66e46fe..ba88aa8f 100644
--- a/include/r-tech1/input/input-manager.h
+++ b/include/r-tech1/input/input-manager.h
@@ -1,330 +1,332 @@
#ifndef _rtech1_input_manager
#define _rtech1_input_manager
#include <vector>
#include <algorithm>
#include "input.h"
#include "input-map.h"
#include "input-source.h"
#include "touch.h"
#include "r-tech1/funcs.h"
#include "r-tech1/pointer.h"
#include "r-tech1/events.h"
#include "keyboard.h"
#include "joystick.h"
#include "touch.h"
#include "r-tech1/exceptions/exception.h"
class Configuration;
class InputSource;
template <class Output>
class InputHandler{
public:
InputHandler(){
}
virtual ~InputHandler(){
}
virtual void press(const Output & out, Keyboard::unicode_t unicode) = 0;
virtual void release(const Output & out, Keyboard::unicode_t unicode) = 0;
};
/* handles keyboard/joystick/whatever input during the game */
class InputManager{
public:
/* main has one instance of this and thats it.
* should the janitor have the reference instead?
*/
friend int rtech_main(int, char**);
friend int main(int, char **);
/* returns true if any input device is activated (keys pressed, joystick button */
static bool anyInput();
+ static const Util::ReferenceCount<DeviceInput::Touch> & getTouch();
+
// static std::vector<Input::PaintownInput> getInput(const Configuration & configuration, const int facing);
static void poll();
/*
static void enableBufferInput();
static void disableBufferInput();
*/
static void waitForKeys(int key1, int key2, const InputSource & source);
static void waitForKeys(int key1, const InputSource & source);
static int readKey();
static void waitForClear();
static void deferResizeEvents(bool defer);
static const std::map<int, Util::ReferenceCount<Joystick> > & getJoysticks();
/*
template <class X>
static void observeKeyboard(InputMap<X> & input){
manager->keyboard.addObserver(InputMap<X>::observeKey, &input);
}
template <class X>
static void unObserveKeyboard(InputMap<X> & input){
manager->keyboard.removeObserver(InputMap<X>::observeKey, &input);
}
*/
static std::vector<Keyboard::unicode_t> readText(){
return manager->keyboard.readText();
}
template <typename X>
static std::vector<Keyboard::unicode_t> readText(InputMap<X> & input, typename InputMap<X>::Output & output){
return manager->_readText(input, output);
}
#if 0
template <typename X>
static typename InputMap<X>::Output getMap(InputMap<X> & input){
if (manager){
return manager->_getMap(input);
}
/* just crash hard.. who cares */
throw Exception::Base(__FILE__, __LINE__);
/* make the compiler happy about returning something */
return *(typename InputMap<X>::Output*)1;
}
#endif
template <typename X>
static typename std::vector<typename InputMap<X>::InputEvent> getEvents(InputMap<X> & input, const InputSource & source){
return manager->_getEvents(input, source);
}
template <typename X>
static void handleEvents(InputMap<X> & input, const InputSource & source, InputHandler<X> & handler){
typename std::vector<typename InputMap<X>::InputEvent> events = getEvents(input, source);
for (typename std::vector<typename InputMap<X>::InputEvent>::iterator it = events.begin(); it != events.end(); it++){
const typename InputMap<X>::InputEvent & event = *it;
if (event.enabled){
handler.press(event.out, event.unicode);
} else {
handler.release(event.out, event.unicode);
}
}
}
template <typename X>
static bool pressed(InputMap<X> & input, const InputSource & source, X out){
if (manager){
return manager->_pressed(input, source, out);
}
return false;
}
/* wait for a key to be released
* really this waits for all inputs that would result in `out'
* being generated to stop.
*/
template <typename X>
static void waitForRelease(InputMap<X> & input, const InputSource & source, X out){
while (InputManager::pressed(input, source, out)){
Util::rest(1);
InputManager::poll();
}
}
template <typename X>
static void waitForPress(InputMap<X> & input, const InputSource & source, X out){
while (!InputManager::pressed(input, source, out)){
Util::rest(1);
InputManager::poll();
}
}
template <typename X>
static void captureInput(InputMap<X> & input){
manager->_captureInput(input);
}
template <typename X>
static void releaseInput(InputMap<X> & input){
manager->_releaseInput(input);
}
protected:
InputManager();
virtual ~InputManager();
virtual bool _anyInput();
virtual int _readKey();
// virtual std::vector<Input::PaintownInput> _getInput(const Configuration & configuration, const int facing);
template <typename X>
void _captureInput(InputMap<X> & input){
capture = (void*) &input;
}
template <typename X>
void _releaseInput(InputMap<X> & input){
if (capture == (void*) &input){
capture = 0;
}
}
template <typename X>
std::vector<Keyboard::unicode_t> _readText(InputMap<X> & input, typename InputMap<X>::Output & output){
std::vector<Keyboard::unicode_t> text;
std::vector<Keyboard::KeyData> all = keyboard.readData();
for (std::vector<Keyboard::KeyData>::iterator it = all.begin(); it != all.end(); it++){
const Keyboard::KeyData & data = *it;
KeyState<X> * state = input.getState(data.key);
if (state != NULL && output[state->out]){
text.push_back(data.unicode);
}
}
return text;
}
std::vector<DeviceInput::Touch::Event> getTouchEvents();
void removeDuplicates(std::vector<int> & storage){
std::vector<int> output;
int last = -1;
for (std::vector<int>::iterator it = storage.begin(); it != storage.end(); it++){
if (*it != last){
output.push_back(*it);
last = *it;
}
}
storage = output;
}
template <typename X>
typename std::vector<typename InputMap<X>::InputEvent> _getEvents(InputMap<X> & input, const InputSource & source){
/* FIXME: get events from the source */
std::vector<typename InputMap<X>::InputEvent> events;
if (capture != NULL && capture != &input){
return events;
}
if (source.useKeyboard()){
const std::vector<typename Keyboard::KeyData> & buffer = keyboard.getBufferedKeys();
for (std::vector<Keyboard::KeyData>::const_iterator it = buffer.begin(); it != buffer.end(); it++){
const Keyboard::KeyData & data = *it;
Util::ReferenceCount<KeyState<X> > state = input.getState(data.key);
if (state != NULL){
events.push_back(typename InputMap<X>::InputEvent(state->out, data.unicode, data.enabled));
}
}
}
std::vector<DeviceInput::Touch::Event> touchEvents = getTouchEvents();
for (std::vector<DeviceInput::Touch::Event>::iterator it = touchEvents.begin(); it != touchEvents.end(); it++){
DeviceInput::Touch::Event event = *it;
Util::ReferenceCount<TouchState<X> > state = input.getTouchState(event.key);
if (state != NULL){
events.push_back(typename InputMap<X>::InputEvent(state->out, -1, event.enabled));
}
}
for (std::vector<int>::const_iterator it = source.getJoystick().begin(); it != source.getJoystick().end(); it++){
int config = *it;
if (config >= 0 && config < (int) joysticks.size()){
Util::ReferenceCount<Joystick> joystick = joysticks[config];
if (joystick != NULL){
const std::vector<typename Joystick::Event> & joystickEvents = joystick->getEvents();
for (std::vector<Joystick::Event>::const_iterator it = joystickEvents.begin(); it != joystickEvents.end(); it++){
Joystick::Event event = *it;
Util::ReferenceCount<JoystickState<X> > state = input.getJoystickState(event.key);
if (state != NULL){
events.push_back(typename InputMap<X>::InputEvent(state->out, -1, event.enabled));
}
}
}
}
}
return events;
}
#if 0
template <typename X>
typename InputMap<X>::Output _getMap(InputMap<X> & input){
typename InputMap<X>::Output output;
if (capture != 0 && capture != &input){
return output;
}
std::vector<int> all_keys;
keyboard.readKeys(all_keys);
keyboard.readBufferedKeys(all_keys);
// all_keys.insert(all_keys.end(), bufferedKeys.begin(), bufferedKeys.end());
// all_keys.insert(all_keys.end(), keyboard.currentKeys().begin(), keyboard.currentKeys.end());
std::sort(all_keys.begin(), all_keys.end());
removeDuplicates(all_keys);
// std::unique(all_keys.begin(), all_keys.end());
// bufferedKeys.clear();
input.read(all_keys, &output);
/*
if (joystick != NULL){
JoystickInput all_joystick = joystick->readAll();
input.read(all_joystick, &output);
}
*/
/* just bumps an internal counter */
input.update();
return output;
}
#endif
template <typename X>
bool _pressed(InputMap<X> & input, const InputSource & source, X result){
/* FIXME: use the input source, luke */
if (capture != 0 && capture != &input){
return false;
}
std::vector<int> all_keys;
keyboard.readKeys(all_keys);
// all_keys.insert(all_keys.end(), bufferedKeys.begin(), bufferedKeys.end());
std::sort(all_keys.begin(), all_keys.end());
removeDuplicates(all_keys);
// bufferedKeys.clear();
bool out = false;
out = input.pressed(all_keys, result);
/*
if (joystick != NULL){
JoystickInput all_joystick = joystick->readAll();
out |= input.pressed(all_joystick, result);
}
*/
return out;
}
virtual void _poll();
protected:
void installJoysticks();
void checkJoysticks();
private:
static InputManager * manager;
void * capture;
std::map<int, Util::ReferenceCount<Joystick> > joysticks;
Keyboard keyboard;
Util::ReferenceCount<DeviceInput::Touch> touch;
Util::EventManager eventManager;
// std::vector<int> bufferedKeys;
// bool bufferKeys;
};
#endif
diff --git a/include/r-tech1/input/input-map.h b/include/r-tech1/input/input-map.h
index ac132efb..1316b3cf 100644
--- a/include/r-tech1/input/input-map.h
+++ b/include/r-tech1/input/input-map.h
@@ -1,347 +1,347 @@
#ifndef _rtech1_input_map_h
#define _rtech1_input_map_h
#include <map>
#include <vector>
#include "joystick.h"
#include "keyboard.h"
#include "touch.h"
#include "r-tech1/pointer.h"
#include <iostream>
template <typename X>
struct KeyState{
KeyState(unsigned int delay, bool block, X out, unsigned int last_read):
delay(delay),
block(block),
out(out),
pressed(false),
last_read(0),
seen(0){
}
unsigned int delay;
bool block;
X out;
bool pressed;
unsigned int last_read;
unsigned int seen;
};
/* cant typedef a template'd struct so we have to copy/paste the definition
*/
template <typename X>
struct JoystickState{
JoystickState(unsigned int delay, bool block, X out, unsigned int last_read):
delay(delay),
block(block),
out(out),
pressed(false),
last_read(0),
seen(0){
}
unsigned int delay;
bool block;
X out;
bool pressed;
unsigned int last_read;
unsigned int seen;
};
template <typename X>
struct TouchState{
TouchState(X out, unsigned int last_read):
out(out),
pressed(false),
last_read(last_read){
}
X out;
bool pressed;
unsigned int last_read;
};
/* maps a raw input device (keyboard, joystick, etc.) to some user-defined type
* the template parameter, X, is that user-defined type
*/
template <typename X>
class InputMap{
public:
typedef std::map<X, bool> Output;
struct InputEvent{
InputEvent(const X & out, Keyboard::unicode_t unicode, bool enabled):
out(out),
unicode(unicode),
enabled(enabled){
}
InputEvent(const InputEvent & input):
out(input.out),
unicode(input.unicode),
enabled(input.enabled){
}
InputEvent(){
}
bool operator[](const X & is) const {
return this->out == is;
}
X out;
Keyboard::unicode_t unicode;
bool enabled;
};
InputMap():
last_read(0){
}
InputMap(const InputMap & copy){
copyMap(copy);
}
InputMap & operator=(const InputMap & copy){
copyMap(copy);
return *this;
}
void copyMap(const InputMap & copy){
key_states.clear();
for (typename std::map<Keyboard::KeyType, Util::ReferenceCount<KeyState<X> > >::const_iterator it = copy.key_states.begin(); it != copy.key_states.end(); it++){
if (it->second != NULL){
key_states[(*it).first] = Util::ReferenceCount<KeyState<X> >(new KeyState<X>(*(*it).second));
}
}
joy_states.clear();
for (typename std::map<typename Joystick::Key, Util::ReferenceCount<JoystickState<X> > >::const_iterator it = copy.joy_states.begin(); it != copy.joy_states.end(); it++){
if (it->second != NULL){
joy_states[(*it).first] = Util::ReferenceCount<JoystickState<X> >(new JoystickState<X>(*(*it).second));
}
}
touch_states.clear();
- for (typename std::map<typename DeviceInput::Touch::Key, Util::ReferenceCount<TouchState<X> > >::const_iterator it = copy.joy_states.begin(); it != copy.joy_states.end(); it++){
+ for (typename std::map<typename DeviceInput::Touch::Key, Util::ReferenceCount<TouchState<X> > >::const_iterator it = copy.touch_states.begin(); it != copy.touch_states.end(); it++){
if (it->second != NULL){
touch_states[(*it).first] = Util::ReferenceCount<TouchState<X> >(new TouchState<X>(*(*it).second));
}
}
last_read = copy.last_read;
}
virtual ~InputMap(){
/* map will clear itself, reference count will delete all objects */
}
/* key: the keyboard key to recognize, something like KEY_A
* delay: time before successive keys are recognized (if held down)
* block: if true then the key must be released before it will
* be recognized again. false allows repetition.
* out: user defined value to set if this key is pressed
*/
void set(Keyboard::KeyType key, int delay, bool block, X out){
key_states[key] = Util::ReferenceCount<KeyState<X> >(new KeyState<X>(delay, block, out, last_read));
}
void set(Keyboard::KeyType key, X out){
set(key, 0, false, out);
}
/* change an existing key */
void update(Keyboard::KeyType key, int delay, bool block, X out){
if (key_states[key] != 0){
key_states[key]->delay = delay;
key_states[key]->block = block;
key_states[key]->out = out;
}
}
void set(typename DeviceInput::Touch::Key key, X out){
touch_states[key] = Util::ReferenceCount<TouchState<X> >(new TouchState<X>(out, last_read));
}
/* mostly the same stuff but for joysticks.
*/
void set(typename Joystick::Key key, int delay, bool block, X out){
joy_states[key] = Util::ReferenceCount<JoystickState<X> >(new JoystickState<X>(delay, block, out, last_read));
}
void set(typename Joystick::Key key, X out){
set(key, 0, false, out);
}
static std::vector<X> getAllPressed(const Output & output){
std::vector<X> out;
for (typename Output::const_iterator it = output.begin(); it != output.end(); it++){
if ((*it).second){
out.push_back((*it).first);
}
}
return out;
}
/*
static void observeKey(const Keyboard::KeyData & data, void * self){
InputMap<X> * me = (InputMap<X>*) self;
KeyState<X> * state = state = getState(data.key);
if (state != NULL){
events.push_back(InputEvent(state->out, data.unicode, data.enabled));
}
}
*/
bool pressed(const std::vector<int> & keys, X out){
for (std::vector<int>::const_iterator it = keys.begin(); it != keys.end(); it++){
Keyboard::KeyType key = *it;
Util::ReferenceCount<KeyState<X> > state = key_states[key];
if (state != NULL){
if (state->out == out){
return true;
}
}
}
return false;
}
virtual Util::ReferenceCount<KeyState<X> > getState(int key){
return key_states[key];
}
virtual Util::ReferenceCount<TouchState<X> > getTouchState(DeviceInput::Touch::Key key){
return touch_states[key];
}
virtual Util::ReferenceCount<JoystickState<X> > getJoystickState(Joystick::Key key){
return joy_states[key];
}
void read(const std::vector<int> & keys, Output * output){
for (std::vector<int>::const_iterator it = keys.begin(); it != keys.end(); it++){
Keyboard::KeyType key = *it;
Util::ReferenceCount<KeyState<X> > state = getState(key);
if (state != NULL){
bool use = false;
// Global::debug(0) << "read " << key << " last read is " << state->last_read << " my last read is " << last_read << std::endl;
if (state->block){
if (last_read - state->last_read > 1){
use = true;
}
} else if (last_read - state->last_read > 1 || state->seen >= state->delay){
use = true;
state->seen = 0;
} else {
state->seen += 1;
}
state->last_read = last_read;
// state->last_read = last_read;
(*output)[state->out] = use;
}
}
}
const std::map<Keyboard::KeyType, Util::ReferenceCount<KeyState<X> > > & getKeyStates() const {
return key_states;
}
/* called by the input manager when the map is read */
void update(){
last_read += 1;
}
void read(const JoystickInput & joystick, Output * output){
#define do_joy(field, key) if (joystick.field){\
Util::ReferenceCount<JoystickState<X> > state = joy_states[Joystick::key];\
doJoyState(state, output);\
}
do_joy(down, Down);
do_joy(up, Up);
do_joy(left, Left);
do_joy(right, Right);
do_joy(button1, Button1);
do_joy(button2, Button2);
do_joy(button3, Button3);
do_joy(button4, Button4);
do_joy(button5, Button5);
do_joy(button6, Button6);
do_joy(quit, Quit);
do_joy(start, Start);
/*
if (joystick.up){
JoystickState<X> * state = joy_states[Joystick::Up];
doJoyState(state);
}
if (joystick.down){
JoystickState<X> * state = joy_states[Joystick::Down];
doJoyState(state);
}
*/
#undef do_joy
}
bool pressed(const JoystickInput & joystick, X out){
#define do_joy(field, key) if (joystick.field){\
Util::ReferenceCount<JoystickState<X> > state = joy_states[Joystick::key];\
if (state != 0 && state->out == out){\
return true;\
}\
}
do_joy(down, Down);
do_joy(up, Up);
do_joy(left, Left);
do_joy(right, Right);
do_joy(button1, Button1);
do_joy(button2, Button2);
do_joy(button3, Button3);
do_joy(button4, Button4);
do_joy(button5, Button5);
do_joy(button6, Button6);
do_joy(quit, Quit);
do_joy(start, Start);
#undef do_joy
return false;
}
protected:
void doJoyState(JoystickState<X> * state, Output * output){
if (state != NULL){
bool use = false;
if (state->block){
if (last_read - state->last_read > 1){
use = true;
}
} else if (last_read - state->last_read > 1 || state->seen >= state->delay){
use = true;
state->seen = 0;
} else {
state->seen += 1;
}
state->last_read = last_read;
// state->last_read = last_read;
(*output)[state->out] = use;
}
}
private:
std::map<Keyboard::KeyType, Util::ReferenceCount<KeyState<X> > > key_states;
std::map<typename Joystick::Key, Util::ReferenceCount<JoystickState<X> > > joy_states;
std::map<typename DeviceInput::Touch::Key, Util::ReferenceCount<TouchState<X> > > touch_states;
unsigned int last_read;
};
#endif
diff --git a/include/r-tech1/input/touch.h b/include/r-tech1/input/touch.h
index 3af8546f..28f16623 100644
--- a/include/r-tech1/input/touch.h
+++ b/include/r-tech1/input/touch.h
@@ -1,64 +1,72 @@
#ifndef _rtech1_touch
#define _rtech1_touch
#include "../pointer.h"
#include <vector>
+namespace Graphics{
+ class Bitmap;
+}
+
/* Manages devices that respond to touch input, such as android/ios
*
* A specific area of the screen will correspond to specific buttons. Something like
* (0, 0) - (10, 10) = up button
* (0, 10) - (10, 20) = down button
*
* When a touch occurs in an area defined with a button then a logical key press will be created.
*
* The scroll events will be generated when a touch is registered outside a button area and
* there is movement of a sufficient amount in one direction.
*/
namespace DeviceInput{
class Touch{
public:
Touch();
virtual void poll() = 0;
virtual ~Touch();
enum Key{
Invalid = -1,
Up = 0,
Down,
Left,
Right,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
Quit,
Start
};
+ virtual void setZone(Key key, int x1, int y1, int x2, int y2) = 0;
+
+ virtual void drawTouchOverlay(const Graphics::Bitmap & bitmap) = 0;
+
class Event{
public:
Event(Key key, bool enabled);
Key key;
bool enabled;
};
const std::vector<Event> & getEvents();
std::vector<Event> events;
};
Util::ReferenceCount<Touch> getTouchDevice();
}
#endif
diff --git a/src/events.cpp b/src/events.cpp
index 9048b705..6e0e79a3 100644
--- a/src/events.cpp
+++ b/src/events.cpp
@@ -1,634 +1,636 @@
#ifdef USE_SDL
#include <SDL.h>
#endif
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#endif
#include <vector>
#include <map>
#include "r-tech1/graphics/bitmap.h"
#include "r-tech1/events.h"
#include "r-tech1/exceptions/shutdown_exception.h"
#include "r-tech1/configuration.h"
#include "r-tech1/debug.h"
#include "r-tech1/funcs.h"
#include "r-tech1/thread.h"
#include "r-tech1/init.h"
#include "r-tech1/parameter.h"
#include "r-tech1/input/keyboard.h"
#include "r-tech1/input/joystick.h"
#include "r-tech1/input/input-manager.h"
#include "r-tech1/input/input-source.h"
#include "r-tech1/system.h"
using std::map;
namespace Util{
int do_shutdown = 0;
bool shutdown(){
return do_shutdown > 0;
}
EventManager::EventManager():
bufferKeys(false),
deferResize(false){
resize.enable = false;
#ifdef USE_ALLEGRO5
queue = al_create_event_queue();
if (al_is_keyboard_installed()){
al_register_event_source(queue, al_get_keyboard_event_source());
}
if (al_is_joystick_installed()){
al_register_event_source(queue, al_get_joystick_event_source());
}
if (Graphics::the_display != NULL){
al_register_event_source(queue, al_get_display_event_source(Graphics::the_display));
}
#endif
}
#ifdef USE_SDL
static void handleKeyDown(Keyboard & keyboard, const SDL_Event & event){
keyboard.press(event.key.keysym.sym, event.key.keysym.unicode);
}
static void handleKeyUp(Keyboard & keyboard, const SDL_Event & event){
keyboard.release(event.key.keysym.sym);
}
static void handleJoystickButtonUp(map<int, ReferenceCount<Joystick> > joysticks, const SDL_Event & event){
int device = event.jbutton.which;
int button = event.jbutton.button;
ReferenceCount<Joystick> joystick = joysticks[device];
if (joystick != NULL){
joystick->releaseButton(button);
}
}
static void handleJoystickHat(map<int, ReferenceCount<Joystick> > joysticks, const SDL_Event & event){
int device = event.jhat.which;
int motion = event.jhat.value;
ReferenceCount<Joystick> joystick = joysticks[device];
if (joystick != NULL){
joystick->hatMotion(motion);
}
#if 0
/* should up/down control left/right -- flip these values? */
#if WII
const int axis_up_down = 0;
const int axis_left_right = 1;
const int up = 1;
const int down = -1;
const int left = -1;
const int right = 1;
#else
const int axis_up_down = 1;
const int axis_left_right = 0;
const int up = -1;
const int down = 1;
const int left = -1;
const int right = 1;
#endif
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: joystick->axisMotion(axis_up_down, up); break;
case SDL_HAT_DOWN: joystick->axisMotion(axis_up_down, down); break;
case SDL_HAT_RIGHT: joystick->axisMotion(axis_left_right, right); break;
case SDL_HAT_LEFT: joystick->axisMotion(axis_left_right, left); break;
default: break;
}
#endif
}
static void handleJoystickButtonDown(map<int, ReferenceCount<Joystick> > joysticks, const SDL_Event & event){
int device = event.jbutton.which;
int button = event.jbutton.button;
ReferenceCount<Joystick> joystick = joysticks[device];
if (joystick != NULL){
joystick->pressButton(button);
}
}
static void handleJoystickAxis(map<int, ReferenceCount<Joystick> > joysticks, const SDL_Event & event){
int device = event.jaxis.which;
int axis = event.jaxis.axis;
int value = event.jaxis.value;
ReferenceCount<Joystick> joystick = joysticks[device];
if (joystick != NULL){
joystick->axisMotion(axis, value);
}
}
void EventManager::runSDL(Keyboard & keyboard, map<int, ReferenceCount<Joystick> > joysticks){
keyboard.poll();
for (map<int, ReferenceCount<Joystick> >::iterator it = joysticks.begin(); it != joysticks.end(); it++){
ReferenceCount<Joystick> joystick = it->second;
if (joystick != NULL){
joystick->poll();
}
}
SDL_Event event;
/* FIXME: android gets into an infinite loop while reading events */
#ifdef ANDROID
// int good = SDL_PollEvent(&event);
// for (int check = 0; check < 10 && good; check++, good = SDL_PollEvent(&event)){
// if (SDL_PollEvent(&event) == 1){
while (SDL_PollEvent(&event) == 1){
#else
while (SDL_PollEvent(&event) == 1){
#endif
switch (event.type){
case SDL_QUIT : {
dispatch(CloseWindow);
break;
}
case SDL_KEYDOWN : {
handleKeyDown(keyboard, event);
// dispatch(Key, event.key.keysym.sym);
break;
}
case SDL_KEYUP : {
handleKeyUp(keyboard, event);
break;
}
case SDL_JOYBUTTONDOWN: {
handleJoystickButtonDown(joysticks, event);
break;
}
case SDL_JOYHATMOTION : {
handleJoystickHat(joysticks, event);
break;
}
case SDL_JOYBUTTONUP: {
handleJoystickButtonUp(joysticks, event);
break;
}
case SDL_JOYAXISMOTION: {
handleJoystickAxis(joysticks, event);
break;
}
case SDL_VIDEORESIZE : {
int width = event.resize.w;
int height = event.resize.h;
/* to keep the perspective correct
* 640/480 = 1.33333
*/
/*
double ratio = (double) 640 / (double) 480;
if (width > height){
height = (int)((double) width / ratio);
} else {
width = (int)((double) height * ratio);
}
*/
dispatch(ResizeScreen, width, height);
break;
}
default : {
break;
}
}
}
}
#endif
#ifdef USE_ALLEGRO
void EventManager::runAllegro(Keyboard & keyboard, map<int, ReferenceCount<Joystick> > joystick){
keyboard.poll();
}
#endif
#ifdef USE_ALLEGRO5
static void handleKeyDown(Keyboard & keyboard, const ALLEGRO_EVENT & event){
keyboard.press(event.keyboard.keycode, event.keyboard.unichar);
}
static void handleKeyUp(Keyboard & keyboard, const ALLEGRO_EVENT & event){
keyboard.release(event.keyboard.keycode);
}
static void handleResize(const ALLEGRO_EVENT & event){
double width = event.display.width;
double height = event.display.height;
/*
if (width < 640){
width = 640;
}
if (height < 480){
height = 480;
}
*/
/* to keep the perspective correct
* 640/480 = 1.33333
*/
/*
double ratio = (double) 640 / (double) 480;
if (width > height){
height = width / ratio;
} else {
width = height * ratio;
}
*/
ALLEGRO_DISPLAY * display = event.display.source;
al_acknowledge_resize(display);
Configuration::setScreenWidth((int) width);
Configuration::setScreenHeight((int) height);
al_resize_display(display, (int) width, (int) height);
Graphics::getScreenBuffer()->clear();
/*
ALLEGRO_TRANSFORM transformation;
al_identity_transform(&transformation);
// al_scale_transform(&transformation, (double) al_get_display_width(display) / (double) GFX_X, (double) al_get_display_height(display) / (double) GFX_Y);
al_scale_transform(&transformation, (double) width / (double) GFX_X, (double) height / (double) GFX_Y);
al_set_target_bitmap(Graphics::getScreenBuffer()->getData()->getBitmap());
al_use_transform(&transformation);
*/
}
void EventManager::runAllegro5(Keyboard & keyboard, const map<int, ReferenceCount<Joystick> > & joysticks){
keyboard.poll();
for (map<int, ReferenceCount<Joystick> >::const_iterator it = joysticks.begin(); it != joysticks.end(); it++){
ReferenceCount<Joystick> joystick = it->second;
if (joystick != NULL){
joystick->poll();
}
}
ALLEGRO_EVENT event;
while (al_get_next_event(queue, &event)){
switch (event.type){
/*
case ALLEGRO_EVENT_KEY_DOWN: {
Global::debug(0) << "Key down " << event.keyboard.keycode << std::endl;
handleKeyDown(keyboard, event);
break;
}
*/
case ALLEGRO_EVENT_DISPLAY_RESIZE: {
handleResize(event);
break;
}
case ALLEGRO_EVENT_DISPLAY_CLOSE: {
throw ShutdownException();
break;
}
case ALLEGRO_EVENT_KEY_UP: {
handleKeyUp(keyboard, event);
break;
}
case ALLEGRO_EVENT_KEY_CHAR : {
// Global::debug(0) << "Key char " << event.keyboard.keycode << " unicode " << event.keyboard.unichar << std::endl;
bool ok = true;
if (event.keyboard.repeat){
ok = Keyboard::getRepeatState();
}
if (ok){
handleKeyDown(keyboard, event);
}
break;
}
case ALLEGRO_EVENT_JOYSTICK_CONFIGURATION: {
/* FIXME: tell input manager to reconfigure joysticks */
// al_reconfigure_joysticks();
break;
}
}
}
/*
if (joystick){
joystick->poll();
}
SDL_Event event;
while (SDL_PollEvent(&event) == 1){
switch (event.type){
case SDL_QUIT : {
dispatch(CloseWindow);
break;
}
case SDL_KEYDOWN : {
handleKeyDown(keyboard, event);
// dispatch(Key, event.key.keysym.sym);
break;
}
case SDL_KEYUP : {
handleKeyUp(keyboard, event);
break;
}
case SDL_JOYBUTTONDOWN: {
if (joystick != NULL){
handleJoystickButtonDown(joystick, event);
}
break;
}
case SDL_JOYHATMOTION : {
if (joystick != NULL){
handleJoystickHat(joystick, event);
}
break;
}
case SDL_JOYBUTTONUP: {
if (joystick != NULL){
handleJoystickButtonUp(joystick, event);
}
break;
}
case SDL_JOYAXISMOTION: {
if (joystick != NULL){
handleJoystickAxis(joystick, event);
}
break;
}
case SDL_VIDEORESIZE : {
int width = event.resize.w;
int height = event.resize.h;
/ * to keep the perspective correct
* 640/480 = 1.33333
* /
if (width > height){
height = (int)((double) width / 1.3333333333);
} else {
width = (int)((double) height * 1.3333333333);
}
dispatch(ResizeScreen, width, height);
break;
}
default : {
break;
}
}
}
*/
}
#endif
void EventManager::run(Keyboard & keyboard, std::map<int, ReferenceCount<Joystick> > joysticks){
#ifdef USE_SDL
runSDL(keyboard, joysticks);
#elif USE_ALLEGRO
runAllegro(keyboard, joysticks);
#elif USE_ALLEGRO5
runAllegro5(keyboard, joysticks);
#endif
}
/* kill the program if the user requests */
void EventManager::waitForThread(WaitThread & thread){
// Keyboard dummy;
while (!thread.isRunning()){
try{
/* input manager will run the event manager */
InputManager::poll();
// run(dummy);
} catch (const ShutdownException & death){
thread.kill();
throw death;
}
Util::rest(10);
}
}
EventManager::~EventManager(){
#ifdef USE_ALLEGRO5
al_destroy_event_queue(queue);
#endif
}
void EventManager::enableKeyBuffer(){
bufferKeys = true;
}
void EventManager::disableKeyBuffer(){
bufferKeys = false;
}
void EventManager::dispatch(Event type, int arg1){
switch (type){
case Key : {
if (bufferKeys){
keys.push_back(KeyType(arg1));
}
break;
}
default : {
break;
}
}
}
void EventManager::dispatch(Event type, int arg1, int arg2){
switch (type){
case ResizeScreen : {
if (deferResize){
resize.type = ResizeScreen;
resize.width = arg1;
resize.height = arg2;
resize.enable = true;
} else {
Global::debug(1) << "Resizing screen to " << arg1 << ", " << arg2 << std::endl;
if (Graphics::setGraphicsMode(0, arg1, arg2) == 0){
Configuration::setScreenWidth(arg1);
Configuration::setScreenHeight(arg2);
}
}
break;
}
default: break;
}
}
void EventManager::dispatch(Event type){
switch (type){
case CloseWindow : {
throw ShutdownException();
}
default : break;
}
}
void EventManager::deferResizeEvents(bool defer){
deferResize = defer;
if (!deferResize && resize.enable){
dispatch(resize.type, resize.width, resize.height);
resize.enable = false;
}
}
class LoopDone: public std::exception {
public:
LoopDone(){
}
~LoopDone() throw () {
}
};
Logic::~Logic(){
}
Draw::Draw():
frames(0),
second_counter(Global::second_counter),
fps(0){
}
void Draw::drawFirst(const Graphics::Bitmap & screen){
draw(screen);
}
Draw::~Draw(){
}
double Draw::getFps() const {
return fps;
}
void Draw::updateFrames(){
if (second_counter != Global::second_counter){
int difference = Global::second_counter - second_counter;
double alpha = 0.2;
/* unlikely, but just in case */
if (difference == 0){
difference = 1;
}
fps = (alpha * fps) + ((1 - alpha) * (double) frames / difference);
// fps[fps_index] = (double) frames / (double) difference;
// fps_index = (fps_index+1) % max_fps_index;
second_counter = Global::second_counter;
frames = 0;
}
frames += 1;
}
static void changeScreenMode(){
Configuration::setFullscreen(!Configuration::getFullscreen());
int gfx = (Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED);
Graphics::changeGraphicsMode(gfx, Graphics::Bitmap::getScreenWidth(), Graphics::Bitmap::getScreenHeight());
}
static void checkFullscreen(){
InputMap<int> input;
input.set(Keyboard::Key_F11, 0, true, 5);
std::vector<InputMap<int>::InputEvent> events = InputManager::getEvents(input, InputSource(true));
for (std::vector<InputMap<int>::InputEvent>::iterator it = events.begin(); it != events.end(); it++){
InputMap<int>::InputEvent event = *it;
if (!event.enabled){
continue;
}
if (event.out == 5){
changeScreenMode();
}
}
}
static void doStandardLoop(Logic & logic, Draw & draw){
if (Graphics::screenParameter.current() == NULL){
throw Exception::Base(__FILE__, __LINE__);
}
const Graphics::Bitmap & screen = *Graphics::screenParameter.current();
screen.clear();
draw.drawFirst(screen.aspectRatio(640, 480));
screen.BlitToScreen();
Global::speed_counter4 = 0;
double runCounter = 0;
try{
const int maxCount = 20;
int frameCount = 0;
uint64_t frameTime = 0;
int logicCount = 0;
uint64_t logicTime = 0;
while (!logic.done()){
if (Global::speed_counter4 > 0){
// Global::debug(0) << "Speed counter " << Global::speed_counter4 << std::endl;
runCounter += logic.ticks(Global::speed_counter4);
Global::speed_counter4 = 0;
bool need_draw = false;
while (runCounter >= 1.0){
need_draw = true;
InputManager::poll();
checkFullscreen();
runCounter -= 1;
logicCount += 1;
uint64_t now = System::currentMilliseconds();
logic.run();
uint64_t later = System::currentMilliseconds();
logicTime += (later - now);
if (logicCount >= maxCount){
// Global::debug(0) << "Logic average " << (logicTime / logicCount) << "ms" << std::endl;
logicCount = 0;
logicTime = 0;
}
if (shutdown()){
throw ShutdownException();
}
if (logic.done()){
/* quit the loop immediately */
throw LoopDone();
}
}
if (need_draw){
frameCount += 1;
draw.updateFrames();
uint64_t now = System::currentMilliseconds();
screen.clear();
draw.draw(screen.aspectRatio(640, 480));
+ InputManager::getTouch()->drawTouchOverlay(screen);
screen.BlitToScreen();
uint64_t later = System::currentMilliseconds();
frameTime += (later - now);
if (frameCount >= maxCount){
// Global::debug(0) << "Draw average " << (frameTime / frameCount) << "ms" << std::endl;
frameCount = 0;
frameTime = 0;
}
}
}
while (Global::speed_counter4 == 0){
/* if the fps is limited then don't keep redrawing */
if (Global::rateLimit){
rest(1);
} else {
draw.updateFrames();
screen.clear();
draw.draw(screen.aspectRatio(640, 480));
+ InputManager::getTouch()->drawTouchOverlay(screen);
screen.BlitToScreen();
}
}
}
} catch (const LoopDone & done){
}
}
void standardLoop(Logic & logic, Draw & draw){
/* if a screen already exists (because we have nested standardLoops) then
* leave this parameter alone, otherwise set a new parameter.
*/
/*
if (Parameter<Graphics::Bitmap*>::current() == NULL){
doStandardLoop(logic, draw);
} else {
doStandardLoop(logic, draw);
}
*/
doStandardLoop(logic, draw);
}
}
diff --git a/src/graphics/allegro5/bitmap.cpp b/src/graphics/allegro5/bitmap.cpp
index 27357329..aea0df99 100644
--- a/src/graphics/allegro5/bitmap.cpp
+++ b/src/graphics/allegro5/bitmap.cpp
@@ -1,1647 +1,1649 @@
#include <sstream>
#include <allegro5/allegro5.h>
#include <allegro5/allegro_memfile.h>
#include <allegro5/allegro_primitives.h>
#include "r-tech1/debug.h"
#include "r-tech1/thread.h"
+#include "r-tech1/input/touch.h"
+#include "r-tech1/input/input-manager.h"
#include <vector>
namespace Graphics{
ALLEGRO_DISPLAY * the_display = NULL;
static std::vector<Util::ReferenceCount<Shader> > shaders;
// static ALLEGRO_SHADER * shader_default;
static Util::ReferenceCount<Shader> shader_shadow;
static Util::ReferenceCount<Shader> shader_lit_sprite;
enum BlendingType{
Translucent,
Add,
Difference,
Multiply
};
struct BlendingData{
BlendingData():
red(0), green(0), blue(0), alpha(0), type(Translucent){
}
int red, green, blue, alpha;
BlendingType type;
};
static BlendingData globalBlend;
Color makeColorAlpha(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha){
return Color(al_map_rgba(red, green, blue, alpha));
}
Color MaskColor(){
static Color mask = makeColorAlpha(0, 0, 0, 0);
return mask;
}
Color getBlendColor(){
/* sort of a hack */
if (globalBlend.type == Multiply){
return makeColorAlpha(255, 255, 255, 255);
}
return makeColorAlpha(255, 255, 255, globalBlend.alpha);
}
Color doTransBlend(const Color & color, int alpha){
unsigned char red, green, blue;
al_unmap_rgb(color.color, &red, &green, &blue);
return makeColorAlpha(red, green, blue, alpha);
/*
red *= alpha_f;
green *= alpha_f;
blue *= alpha_f;
return al_map_rgb_f(red, green, blue);
*/
}
Color transBlendColor(const Color & color){
return doTransBlend(color, globalBlend.alpha);
}
int getRealWidth(const Bitmap & what){
return al_get_bitmap_width(what.getData()->getBitmap());
}
int getRealHeight(const Bitmap & what){
return al_get_bitmap_height(what.getData()->getBitmap());
}
class Blender{
public:
Blender(){
}
virtual ~Blender(){
/* default is to draw the source and ignore the destination */
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
}
};
class MaskedBlender: public Blender {
public:
MaskedBlender(){
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
}
};
class LitBlender: public Blender {
public:
LitBlender(ALLEGRO_COLOR lit){
// al_set_blend_color(lit);
// al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE_MINUS_DST_COLOR, ALLEGRO_ZERO);
}
};
class TransBlender: public Blender {
public:
TransBlender(){
switch (globalBlend.type){
case Translucent: al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); break;
case Add: al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); break;
case Multiply: al_set_blender(ALLEGRO_ADD, ALLEGRO_DEST_COLOR, ALLEGRO_INVERSE_ALPHA); break;
case Difference: al_set_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_ONE, ALLEGRO_ONE); break;
}
}
};
static const int WINDOWED = 0;
static const int FULLSCREEN = 1;
// static Bitmap * Scaler = NULL;
Bitmap::Bitmap():
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)),
width(0),
height(0){
/* TODO */
}
Bitmap::Bitmap( const char * load_file ):
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)){
internalLoadFile(load_file);
width = al_get_bitmap_width(getData()->getBitmap());
height = al_get_bitmap_height(getData()->getBitmap());
}
Bitmap::Bitmap( const std::string & load_file ):
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)){
internalLoadFile(load_file.c_str());
width = al_get_bitmap_width(getData()->getBitmap());
height = al_get_bitmap_height(getData()->getBitmap());
}
Bitmap::Bitmap(ALLEGRO_BITMAP * who, bool deep_copy):
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)){
if (deep_copy){
ALLEGRO_BITMAP * clone = al_clone_bitmap(who);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(clone)));
} else {
setData(Util::ReferenceCount<BitmapData>(new BitmapData(who)));
}
this->width = al_get_bitmap_width(getData()->getBitmap());
this->height = al_get_bitmap_height(getData()->getBitmap());
}
Bitmap::Bitmap(int width, int height):
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)){
ALLEGRO_BITMAP * bitmap = al_create_bitmap(width, height);
if (bitmap == NULL){
std::ostringstream out;
out << "Could not create bitmap with dimensions " << width << ", " << height;
throw BitmapException(__FILE__, __LINE__, out.str());
}
/*
if (al_get_bitmap_flags(bitmap) & ALLEGRO_VIDEO_BITMAP){
ALLEGRO_BITMAP * old = al_get_target_bitmap();
al_set_target_bitmap(bitmap);
al_use_shader(shader_default);
al_set_target_bitmap(old);
}
*/
setData(Util::ReferenceCount<BitmapData>(new BitmapData(bitmap)));
this->width = al_get_bitmap_width(getData()->getBitmap());
this->height = al_get_bitmap_height(getData()->getBitmap());
}
Bitmap::Bitmap(const Bitmap & copy, bool deep_copy):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor),
width(copy.width),
height(copy.height){
if (deep_copy){
ALLEGRO_BITMAP * clone = al_clone_bitmap(copy.getData()->getBitmap());
setData(Util::ReferenceCount<BitmapData>(new BitmapData(clone)));
} else {
setData(copy.getData());
}
}
Bitmap Bitmap::createMemoryBitmap(int width, int height){
int flags = al_get_new_bitmap_flags();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
Bitmap out = Bitmap(width, height);
al_set_new_bitmap_flags(flags);
return out;
}
void Bitmap::convertToVideo(){
ALLEGRO_BITMAP * original = getData()->getBitmap();
ALLEGRO_BITMAP * copy = al_clone_bitmap(original);
if (copy == NULL){
throw BitmapException(__FILE__, __LINE__, "Could not create video bitmap");
}
al_destroy_bitmap(getData()->getBitmap());
getData()->setBitmap(copy);
/*
if (al_get_bitmap_flags(copy) & ALLEGRO_VIDEO_BITMAP){
ALLEGRO_BITMAP * old = al_get_target_bitmap();
al_set_target_bitmap(copy);
al_use_shader(shader_default);
al_set_target_bitmap(old);
}
*/
}
void changeTarget(const Bitmap & from, const Bitmap & who){
/* pray that if drawing is held then who is already the current target */
if (!al_is_bitmap_drawing_held()){
if (al_get_target_bitmap() != who.getData()->getBitmap()){
al_set_target_bitmap(who.getData()->getBitmap());
}
if ((al_get_bitmap_flags(who.getData()->getBitmap()) & ALLEGRO_VIDEO_BITMAP) &&
(al_get_bitmap_flags(from.getData()->getBitmap()) & ALLEGRO_MEMORY_BITMAP)){
((Bitmap&) from).convertToVideo();
/* How can from == who? If they were the same then the bitmap flags above
* would not have been different.
*/
if (&from == &who){
al_set_target_bitmap(who.getData()->getBitmap());
}
}
}
}
void changeTarget(const Bitmap * from, const Bitmap & who){
changeTarget(*from, who);
}
void changeTarget(const Bitmap & from, const Bitmap * who){
changeTarget(from, *who);
}
void changeTarget(const Bitmap * from, const Bitmap * who){
changeTarget(*from, *who);
}
void dumpColor(const Color & color){
unsigned char red, green, blue, alpha;
al_unmap_rgba(color.color, &red, &green, &blue, &alpha);
Global::debug(0) << "red " << (int) red << " green " << (int) green << " blue " << (int) blue << " alpha " << (int) alpha << std::endl;
}
Color pcxMaskColor(unsigned char * data, const int length){
if (length >= 769){
if (data[length - 768 - 1] == 12){
unsigned char * palette = &data[length - 768];
unsigned char red = palette[0];
unsigned char green = palette[1];
unsigned char blue = palette[2];
return makeColorAlpha(red, green, blue, 255);
}
}
return makeColorAlpha(255, 255, 255, 255);
}
Bitmap memoryPCX(unsigned char * const data, const int length, const bool mask){
ALLEGRO_FILE * memory = al_open_memfile((void *) data, length, "r");
ALLEGRO_BITMAP * pcx = al_load_bitmap_f(memory, ".pcx");
al_fclose(memory);
if (pcx == NULL){
throw BitmapException(__FILE__, __LINE__, "Could not load pcx");
}
// dumpColor(al_get_pixel(pcx, 0, 0));
Bitmap out(pcx);
out.set8BitMaskColor(pcxMaskColor(data, length));
return out;
}
static bool isVideoBitmap(ALLEGRO_BITMAP * bitmap){
return (al_get_bitmap_flags(bitmap) & ALLEGRO_VIDEO_BITMAP) &&
!(al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP);
}
void Bitmap::replaceColor(const Color & original, const Color & replaced){
changeTarget(this, this);
if (isVideoBitmap(getData()->getBitmap())){
al_lock_bitmap(getData()->getBitmap(), ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE);
}
int width = getRealWidth(*this);
int height = getRealHeight(*this);
for (int x = 0; x < width; x++){
for (int y = 0; y < height; y++){
Color pixel = getPixel(x, y);
if (pixel == original){
al_put_pixel(x, y, replaced.color);
}
}
}
if (isVideoBitmap(getData()->getBitmap())){
al_unlock_bitmap(getData()->getBitmap());
}
}
static ALLEGRO_BITMAP * memoryGIF(const char * data, int length){
ALLEGRO_FILE * memory = al_open_memfile((void *) data, length, "r");
al_fclose(memory);
/* FIXME: get gif addon for a5 */
#if 0
RGB * palette = NULL;
/* algif will close the packfile for us in both error and success cases */
BITMAP * gif = load_gif_packfile(pack, palette);
if (!gif){
al_fclose(memory);
// pack_fclose(pack);
ostringstream out;
out <<"Could not load gif from memory: " << (void*) data << " length " << length;
throw LoadException(__FILE__, __LINE__, out.str());
}
BITMAP * out = create_bitmap(gif->w, gif->h);
blit(gif, out, 0, 0, 0, 0, gif->w, gif->h);
destroy_bitmap(gif);
// pack_fclose(pack);
#endif
ALLEGRO_BITMAP * out = NULL;
return out;
}
void Bitmap::internalLoadFile(const char * path){
this->path = path;
ALLEGRO_BITMAP * loaded = al_load_bitmap(path);
if (loaded == NULL){
std::ostringstream out;
out << "Could not load file '" << path << "'";
throw BitmapException(__FILE__, __LINE__, out.str());
}
al_convert_mask_to_alpha(loaded, al_map_rgb(255, 0, 255));
setData(Util::ReferenceCount<BitmapData>(new BitmapData(loaded)));
}
static ALLEGRO_BITMAP * do_load_from_memory(const char * data, int length, const char * type){
ALLEGRO_FILE * memory = al_open_memfile((void*) data, length, "r");
ALLEGRO_BITMAP * bitmap = al_load_bitmap_f(memory, type);
al_fclose(memory);
al_convert_mask_to_alpha(bitmap, al_map_rgb(255, 0, 255));
return bitmap;
}
static ALLEGRO_BITMAP * load_bitmap_from_memory(const char * data, int length, ImageFormat type){
switch (type){
case FormatBMP: return do_load_from_memory(data, length, ".bmp");
case FormatPNG: return do_load_from_memory(data, length, ".png");
case FormatJPG: return do_load_from_memory(data, length, ".jpg");
case FormatPCX: return do_load_from_memory(data, length, ".pcx");
case FormatTGA: return do_load_from_memory(data, length, ".tga");
case FormatTIF: return do_load_from_memory(data, length, ".tif");
case FormatXPM: return do_load_from_memory(data, length, ".xpm");
case FormatUnknown: break;
case FormatGIF : {
return memoryGIF(data, length);
break;
}
}
std::ostringstream out;
out << "Could not load the bitmap because its format was not known";
throw BitmapException(__FILE__, __LINE__, out.str());
}
Bitmap::Bitmap(const char * data, int length):
mustResize(false),
bit8MaskColor(makeColor(0, 0, 0)){
loadFromMemory(data, length);
}
void Bitmap::loadFromMemory(const char * data, int length){
setData(Util::ReferenceCount<BitmapData>(new BitmapData(load_bitmap_from_memory(data, length, identifyImage((const unsigned char *) data, length)))));
if (getData()->getBitmap() == NULL){
std::ostringstream out;
out << "Could not create bitmap from memory";
throw BitmapException(__FILE__, __LINE__, out.str());
}
width = al_get_bitmap_width(getData()->getBitmap());
height = al_get_bitmap_height(getData()->getBitmap());
}
Bitmap::Bitmap( const Bitmap & copy, int x, int y, int width, int height ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor),
width(width),
height(height){
path = copy.getPath();
ALLEGRO_BITMAP * his = copy.getData()->getBitmap();
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (width < 1 || height < 1){
std::ostringstream out;
out << "Attempting to create a sub-bitmap.";
if (width < 1){
out << " Width was less than 1: " << width;
}
if (height < 1){
out << " Height was less than 1: " << height;
}
throw BitmapException(__FILE__, __LINE__, out.str());
}
/*
if (width + x > al_get_bitmap_width(his)){
width = al_get_bitmap_width(his) - x;
}
if (height + y > al_get_bitmap_height(his)){
height = al_get_bitmap_height(his) - y;
}
*/
ALLEGRO_BITMAP * old_target = al_get_target_bitmap();
ALLEGRO_TRANSFORM transform;
al_identity_transform(&transform);
if (al_get_target_bitmap() != copy.getData()->getBitmap()){
al_set_target_bitmap(copy.getData()->getBitmap());
}
if (al_get_current_transform() != NULL){
if (old_target != copy.getData()->getBitmap()){
al_set_target_bitmap(copy.getData()->getBitmap());
}
al_copy_transform(&transform, al_get_current_transform());
}
float x_scaled = x;
float y_scaled = y;
float width_scaled = width;
float height_scaled = height;
al_transform_coordinates(&transform, &x_scaled, &y_scaled);
al_transform_coordinates(&transform, &width_scaled, &height_scaled);
// ALLEGRO_BITMAP * sub = al_create_sub_bitmap(his, x, y, width, height);
ALLEGRO_BITMAP * sub = al_create_sub_bitmap(his, (int) x_scaled, (int) y_scaled, (int) width_scaled, (int) height_scaled);
// ALLEGRO_BITMAP * sub = al_create_sub_bitmap(his, (int) x_scaled, (int) y_scaled, width, height);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(sub)));
al_set_target_bitmap(sub);
al_use_transform(&transform);
al_set_target_bitmap(old_target);
}
static bool isBackBuffer(ALLEGRO_BITMAP * bitmap){
return bitmap == al_get_backbuffer(the_display);
}
int Bitmap::getWidth() const {
/* Always return the true dimensions of the backbuffer */
if (getData() != NULL && isBackBuffer(getData()->getBitmap())){
return al_get_bitmap_width(getData()->getBitmap());
}
return width;
/*
if (getData()->getBitmap() != NULL){
return al_get_bitmap_width(getData()->getBitmap());
}
return 0;
*/
}
int getRed(Color color){
unsigned char red, green, blue;
al_unmap_rgb(color.color, &red, &green, &blue);
return red;
}
int getAlpha(Color color){
unsigned char red, green, blue, alpha;
al_unmap_rgba(color.color, &red, &green, &blue, &alpha);
return alpha;
}
int getGreen(Color color){
unsigned char red, green, blue;
al_unmap_rgb(color.color, &red, &green, &blue);
return green;
}
int getBlue(Color color){
unsigned char red, green, blue;
al_unmap_rgb(color.color, &red, &green, &blue);
return blue;
}
Color makeColor(int red, int blue, int green){
return Color(al_map_rgb(red, blue, green));
}
int Bitmap::getHeight() const {
if (getData() != NULL && isBackBuffer(getData()->getBitmap())){
return al_get_bitmap_height(getData()->getBitmap());
}
return height;
/*
if (getData()->getBitmap() != NULL){
return al_get_bitmap_height(getData()->getBitmap());
}
return 0;
*/
}
void initializeExtraStuff(){
// al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_565);
}
std::string defaultVertexShader(){
return std::string(al_get_default_shader_source(ALLEGRO_SHADER_GLSL, ALLEGRO_VERTEX_SHADER));
}
std::string defaultPixelShader(){
return std::string(al_get_default_shader_source(ALLEGRO_SHADER_GLSL, ALLEGRO_PIXEL_SHADER));
}
void setShaderSampler(ALLEGRO_SHADER * shader, const std::string & name, const Bitmap & texture, int unit){
al_set_shader_sampler(name.c_str(), texture.getData()->getBitmap(), unit);
}
void setShaderBool(ALLEGRO_SHADER * shader, const std::string & name, bool value){
setShaderInt(shader, name, value);
}
void setShaderInt(ALLEGRO_SHADER * shader, const std::string & name, int value){
al_set_shader_int(name.c_str(), value);
}
void setShaderFloat(ALLEGRO_SHADER * shader, const std::string & name, float value){
al_set_shader_float(name.c_str(), value);
}
void setShaderVec4(ALLEGRO_SHADER * shader, const std::string & name, float v1, float v2, float v3, float v4){
float vector[4];
vector[0] = v1;
vector[1] = v2;
vector[2] = v3;
vector[3] = v4;
al_set_shader_float_vector(name.c_str(), 4, &vector[0], 1);
}
static std::string shader_version(const std::string & version, const std::string & data){
std::ostringstream out;
out << "#version " << version << "\n";
out << data;
return out.str();
}
Util::ReferenceCount<Shader> create_shader(const std::string & version, const std::string & vertex, const std::string & pixel){
ALLEGRO_SHADER * shader = al_create_shader(ALLEGRO_SHADER_GLSL);
if (shader == NULL){
return Util::ReferenceCount<Shader>(NULL);
}
if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, shader_version(version, vertex).c_str())){
Global::debug(0) << "attach vertex shader source failed: " << al_get_shader_log(shader) << std::endl << vertex << std::endl;
return Util::ReferenceCount<Shader>(NULL);
}
if (!al_attach_shader_source(shader, ALLEGRO_PIXEL_SHADER, shader_version(version, pixel).c_str())){
Global::debug(0) << "attach pixel shader source failed: " << al_get_shader_log(shader) << std::endl << pixel << std::endl;
Global::debug(0) << "Pixel source: \n" << shader_version(version, pixel) << std::endl;
return Util::ReferenceCount<Shader>(NULL);
}
if (!al_build_shader(shader)){
Global::debug(0) << "shader al_link_shader failed: " << al_get_shader_log(shader) << " pixel: " << pixel << " vertex: " << vertex << std::endl;
return Util::ReferenceCount<Shader>(NULL);
}
return Util::ReferenceCount<Shader>(new Shader(shader));
}
int changeGraphicsMode(int mode, int width, int height){
switch (mode){
case FULLSCREEN: {
al_set_display_flag(the_display, ALLEGRO_FULLSCREEN_WINDOW, true);
break;
}
case WINDOWED: {
al_set_display_flag(the_display, ALLEGRO_FULLSCREEN_WINDOW, false);
break;
}
}
return !al_resize_display(the_display, width, height);
}
static int createShaders(){
try{
shader_shadow = create_shader("100", defaultVertexShader(), Storage::readFile(Storage::instance().find(Filesystem::RelativePath("shaders/shadow.fragment.glsl"))));
if (shader_shadow == NULL){
Global::debug(0) << "Could not create shader for shaders/shadow.fragment.glsl" << std::endl;
return 1;
}
shaders.push_back(shader_shadow);
Global::debug(1) << "Created shadow shader" << std::endl;
} catch (const Filesystem::NotFound & fail){
Global::debug(0) << "Could not load shadow shader: " << fail.getTrace() << std::endl;
return 1;
}
try{
shader_lit_sprite = create_shader("100", defaultVertexShader(), Storage::readFile(Storage::instance().find(Filesystem::RelativePath("shaders/lit-sprite.fragment.glsl"))));
if (shader_lit_sprite == NULL){
return 1;
}
shaders.push_back(shader_lit_sprite);
Global::debug(1) << "Created lit sprite shader" << std::endl;
} catch (const Filesystem::NotFound & fail){
Global::debug(0) << "Could not load lit sprite shader: " << fail.getTrace() << std::endl;
return 1;
}
return 0;
}
int setGraphicsMode(int mode, int width, int height){
initializeExtraStuff();
/* FIXME: the configuration should pass in fullscreen mode here */
#ifdef IPHONE
mode = FULLSCREEN;
#endif
switch (mode){
case FULLSCREEN: {
#ifdef IPHONE
al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE, ALLEGRO_SUGGEST);
al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW | ALLEGRO_PROGRAMMABLE_PIPELINE);
#else
#ifdef ANDROID
al_set_new_display_flags(ALLEGRO_FULLSCREEN | ALLEGRO_PROGRAMMABLE_PIPELINE);
#else
al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW | ALLEGRO_RESIZABLE |
ALLEGRO_OPENGL | ALLEGRO_PROGRAMMABLE_PIPELINE);
#endif
#endif
break;
}
case WINDOWED: {
al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE |
ALLEGRO_PROGRAMMABLE_PIPELINE |
ALLEGRO_OPENGL);
break;
}
default: break;
}
the_display = al_create_display(width, height);
if (the_display == NULL){
std::ostringstream out;
out << "Could not create display with dimensions " << width << ", " << height;
throw BitmapException(__FILE__, __LINE__, out.str());
}
// Global::debug(0) << "Set width " << al_get_display_width(the_display) << " height " << al_get_display_height(the_display) << std::endl;
// Global::debug(0) << "Backbuffer width " << al_get_bitmap_width(al_get_backbuffer(the_display)) << " height " << al_get_bitmap_height(al_get_backbuffer(the_display)) << std::endl;
try{
/* TODO: maybe find a more general way to get the icon */
ALLEGRO_BITMAP * icon = al_load_bitmap(Storage::instance().find(Filesystem::RelativePath("menu/icon.bmp")).path().c_str());
if (icon != NULL){
al_set_display_icon(the_display, icon);
}
} catch (const Filesystem::NotFound & fail){
Global::debug(0) << "Could not set window icon: " << fail.getTrace() << std::endl;
}
Screen = new Bitmap(al_get_backbuffer(the_display));
/* dont destroy the backbuffer */
Screen->getData()->setDestroy(false);
/*
ALLEGRO_TRANSFORM transformation;
al_identity_transform(&transformation);
al_scale_transform(&transformation, (double) Screen->getWidth() / (double) width, (double) Screen->getHeight() / (double) height);
al_set_target_bitmap(Screen->getData()->getBitmap());
al_use_transform(&transformation);
*/
// Scaler = new Bitmap(width, height);
/* default drawing mode */
// al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
// shader_default = create_shader(defaultVertexShader(), defaultPixelShader());
// al_use_shader(shader_default);
/* Default shader */
/*
shader_default = al_create_shader(ALLEGRO_SHADER_GLSL);
al_attach_shader_source(shader_default, ALLEGRO_VERTEX_SHADER, al_get_default_glsl_vertex_shader());
al_attach_shader_source(shader_default, ALLEGRO_PIXEL_SHADER, al_get_default_glsl_pixel_shader());
if (!al_link_shader(shader_default)){
Global::debug(0) << "default shader al_link_shader failed: " << al_get_shader_log(shader_default) << std::endl;
return 1;
}
*/
// al_set_shader(the_display, shader_default);
// shaders.push_back(shader_default);
// Global::debug(1) << "Created default shader" << std::endl;
if (createShaders()){
return 1;
}
return 0;
}
void Bitmap::lock() const {
al_lock_bitmap(getData()->getBitmap(), ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE);
}
void Bitmap::lock(int x, int y, int width, int height) const {
al_lock_bitmap_region(getData()->getBitmap(), x, y, width, height, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE);
}
void Bitmap::unlock() const {
al_unlock_bitmap(getData()->getBitmap());
}
Color Bitmap::getPixel(const int x, const int y) const {
// changeTarget(this, this);
return Color(al_get_pixel(getData()->getBitmap(), x, y));
}
void Bitmap::putPixel(int x, int y, Color pixel) const {
changeTarget(this, this);
// al_put_pixel(x, y, pixel);
al_draw_pixel(x, y, pixel.color);
}
void Bitmap::putPixelNormal(int x, int y, Color col) const {
putPixel(x, y, col);
/*
changeTarget(this, this);
al_put_pixel(x, y, col.color);
*/
}
void Bitmap::fill(Color color) const {
changeTarget(this, this);
al_clear_to_color(color.color);
}
void Bitmap::startDrawing() const {
/* we are about to draw on this bitmap so make sure we are the target */
changeTarget(this, this);
al_hold_bitmap_drawing(true);
}
void Bitmap::endDrawing() const {
al_hold_bitmap_drawing(false);
}
void TranslucentBitmap::startDrawing() const {
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
}
void TranslucentBitmap::endDrawing() const {
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
}
Color Bitmap::blendColor(const Color & input) const {
return input;
}
Color TranslucentBitmap::blendColor(const Color & color) const {
unsigned char red, green, blue;
unsigned char alpha = globalBlend.alpha;
al_unmap_rgb(color.color, &red, &green, &blue);
return makeColorAlpha(red, green, blue, alpha);
}
void Bitmap::StretchHqx(const Bitmap & where, const int sourceX, const int sourceY, const int sourceWidth, const int sourceHeight, const int destX, const int destY, const int destWidth, const int destHeight) const {
/* TODO */
}
void Bitmap::StretchXbr(const Bitmap & where, const int sourceX, const int sourceY, const int sourceWidth, const int sourceHeight, const int destX, const int destY, const int destWidth, const int destHeight) const {
/* TODO */
}
void Bitmap::Stretch(const Bitmap & where, const int sourceX, const int sourceY, const int sourceWidth, const int sourceHeight, const int destX, const int destY, const int destWidth, const int destHeight) const {
changeTarget(this, where);
al_draw_scaled_bitmap(getData()->getBitmap(),
sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight,
0);
}
void Bitmap::StretchBy2(const Bitmap & where){
Stretch(where, 0, 0, getWidth(), getHeight(), 0, 0, getWidth() * 2, getHeight() * 2);
}
void Bitmap::StretchBy4(const Bitmap & where){
Stretch(where, 0, 0, getWidth(), getHeight(), 0, 0, getWidth() * 4, getHeight() * 4);
}
void Bitmap::drawRotate(const int x, const int y, const int angle, const Bitmap & where ){
changeTarget(this, where);
MaskedBlender blender;
al_draw_rotated_bitmap(getData()->getBitmap(), getWidth() / 2, getHeight() / 2, x, y, Util::radians(angle), ALLEGRO_FLIP_HORIZONTAL);
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const Bitmap & where ){
changeTarget(this, where);
MaskedBlender blender;
al_draw_rotated_bitmap(getData()->getBitmap(), getWidth() / 2, getHeight() / 2, x, y, Util::radians(-angle), 0);
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const double scale, const Bitmap & where ){
/* TODO */
}
void Bitmap::drawStretched( const int x, const int y, const int new_width, const int new_height, const Bitmap & who ) const {
/* FIXME */
changeTarget(this, who);
MaskedBlender blender;
al_draw_scaled_bitmap(getData()->getBitmap(), 0, 0, al_get_bitmap_width(getData()->getBitmap()), al_get_bitmap_height(getData()->getBitmap()), x, y, new_width, new_height, 0);
#if 0
ALLEGRO_TRANSFORM save;
al_copy_transform(&save, al_get_current_transform());
ALLEGRO_TRANSFORM stretch;
al_identity_transform(&stretch);
// al_translate_transform(&stretch, x / ((double) new_width / getWidth()), y / ((double) new_height / getHeight()));
al_scale_transform(&stretch, (double) new_width / getWidth(), (double) new_height / getHeight());
al_translate_transform(&stretch, x, y);
// al_translate_transform(&stretch, -x / ((double) new_width / getWidth()), -y / ((double) (new_height / getHeight())));
al_use_transform(&stretch);
/* any source pixels with an alpha value of 0 will be masked */
// al_draw_bitmap(getData().getBitmap(), x, y, 0);
al_draw_bitmap(getData().getBitmap(), 0, 0, 0);
al_use_transform(&save);
#endif
}
Bitmap Bitmap::scaleTo(const int width, const int height) const {
if (width == getRealWidth(*this) && height == getRealHeight(*this)){
return *this;
}
Bitmap scaled(width, height);
changeTarget(*this, scaled);
al_draw_scaled_bitmap(getData()->getBitmap(), 0, 0, getRealWidth(*this), getRealHeight(*this),
0, 0, width, height, 0);
return scaled;
}
void Bitmap::Blit(const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where) const {
// double start = al_get_time();
// changeTarget(this, where);
// al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
/*
if (&where != Screen){
al_draw_bitmap(getData().getBitmap(), wx, wy, 0);
}
*/
changeTarget(this, where);
Bitmap part(*this, mx, my, width, height);
// al_use_shader(shader_default);
// al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
al_draw_bitmap(part.getData()->getBitmap(), wx, wy, 0);
/*
double end = al_get_time();
Global::debug(0) << "Draw in " << (end - start) << " seconds" << std::endl;
*/
}
void Bitmap::drawHFlip(const int x, const int y, const Bitmap & where) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL);
}
void Bitmap::drawHFlip(const int x, const int y, Filter * filter, const Bitmap & where) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL);
}
void Bitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_VERTICAL);
}
void Bitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_VERTICAL);
}
void Bitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void Bitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void Bitmap::BlitMasked(const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where) const {
/* TODO */
}
void Bitmap::BlitToScreen(const int upper_left_x, const int upper_left_y) const {
#if 0
if (getWidth() != Screen->getWidth() || getHeight() != Screen->getHeight()){
/*
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
*/
this->Stretch(*Scaler, 0, 0, getWidth(), getHeight(), upper_left_x, upper_left_y, Scaler->getWidth(), Scaler->getHeight());
Scaler->Blit(0, 0, 0, 0, *Screen);
} else {
this->Blit(upper_left_x, upper_left_y, *Screen);
}
#endif
/*
if (&where == Screen){
al_flip_display();
}
*/
changeTarget(this, Screen);
if (getData()->getBitmap() != Screen->getData()->getBitmap()){
Blit(*Screen);
}
al_flip_display();
}
void Bitmap::BlitAreaToScreen(const int upper_left_x, const int upper_left_y) const {
changeTarget(this, Screen);
/*
if (getData()->getBitmap() != Screen->getData()->getBitmap()){
Blit(upper_left_y, upper_left_y, *Screen);
}
*/
al_flip_display();
}
void Bitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where, int flags) const {
changeTarget(this, where);
MaskedBlender blender;
Util::ReferenceCount<Shader> shader;
if (filter != NULL){
shader = filter->getShader();
}
ALLEGRO_SHADER * a5shader = NULL;
if (shader != NULL){
a5shader = shader->getShader();
}
if (a5shader != NULL){
al_use_shader(a5shader);
filter->setupShader(shader);
}
/* any source pixels with an alpha value of 0 will be masked */
al_draw_bitmap(getData()->getBitmap(), x, y, flags);
if (a5shader != NULL){
al_use_shader(NULL);
}
}
void Bitmap::draw(const int x, const int y, const Bitmap & where) const {
draw(x, y, NULL, where, 0);
/*
// TransBlender blender;
changeTarget(this, where);
MaskedBlender blender;
/ * any source pixels with an alpha value of 0 will be masked * /
al_draw_bitmap(getData()->getBitmap(), x, y, 0);
*/
}
void Bitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where) const {
draw(x, y, filter, where, 0);
}
void Bitmap::drawShadow(Bitmap & where, int x, int y, int intensity, Color color, double scale, bool facingRight) const {
changeTarget(this, where);
MaskedBlender blender;
int newHeight = fabs(scale) * getHeight();
int flags = 0;
if (!facingRight){
flags |= ALLEGRO_FLIP_HORIZONTAL;
}
float shadowColor[4];
al_unmap_rgb_f(color.color, &shadowColor[0], &shadowColor[1], &shadowColor[2]);
shadowColor[3] = (float) intensity / 255.0;
al_use_shader(shader_shadow->getShader());
if (!al_set_shader_float_vector("shadow", 4, shadowColor, 1)){
/* Well.. thats not good. Did the shader source get messed up? */
}
al_draw_scaled_bitmap(getData()->getBitmap(), 0, 0, getWidth(), getHeight(), x, y - newHeight, getWidth(), newHeight, flags);
al_use_shader(NULL);
}
void Bitmap::hLine(const int x1, const int y, const int x2, const Color color) const {
line(x1, y, x2, y, color);
}
void Bitmap::vLine(const int y1, const int x, const int y2, const Color color) const {
line(x, y1, x, y2, color);
}
void Bitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const {
changeTarget(this, this);
al_draw_arc(x, y, radius, ang1 - Util::pi/2, ang2 - ang1, color.color, 1);
}
void TranslucentBitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const {
TransBlender blender;
Bitmap::arc(x, y, ang1, ang2, radius, transBlendColor(color));
/*
changeTarget(this);
al_draw_arc(x, y, radius, ang1 + S_PI/2, ang2 - ang1, doTransBlend(color, globalBlend.alpha), 0);
*/
}
/* from http://www.allegro.cc/forums/thread/605684/892721#target */
#if 0
void al_draw_filled_pieslice(float cx, float cy, float r, float start_theta,
float delta_theta, ALLEGRO_COLOR color){
ALLEGRO_VERTEX vertex_cache[ALLEGRO_VERTEX_CACHE_SIZE];
int num_segments, ii;
num_segments = fabs(delta_theta / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(r));
if (num_segments < 2)
return;
if (num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) {
num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1;
}
al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, r, r, start_theta, delta_theta, 0, num_segments);
vertex_cache[0].x = cx; vertex_cache[0].y = cy;
for (ii = 0; ii < num_segments + 1; ii++) {
vertex_cache[ii].color = color;
vertex_cache[ii].z = 0;
}
al_draw_prim(vertex_cache, NULL, NULL, 0, num_segments + 1, ALLEGRO_PRIM_TRIANGLE_FAN);
// al_draw_prim(vertex_cache, NULL, NULL, 0, 3, ALLEGRO_PRIM_TRIANGLE_FAN);
}
#endif
static float min(float a, float b){
return a < b ? a : b;
}
void Bitmap::roundRect(int radius, int x1, int y1, int x2, int y2, Color color) const {
changeTarget(this, this);
double mx = x2 - x1;
double my = y2 - y1;
double radius_use = min(min(radius, mx / 2), my / 2);
al_draw_rounded_rectangle(x1, y1, x2, y2, radius_use, radius_use, color.color, 1);
}
void TranslucentBitmap::roundRect(int radius, int x1, int y1, int x2, int y2, Color color) const {
TransBlender blender;
Bitmap::roundRect(radius, x1, y1, x2, y2, transBlendColor(color));
}
void Bitmap::roundRectFill(int radius, int x1, int y1, int x2, int y2, Graphics::Color color) const {
changeTarget(this, this);
double mx = x2 - x1;
double my = y2 - y1;
double radius_use = min(min(radius, mx / 2), my / 2);
al_draw_filled_rounded_rectangle(x1, y1, x2, y2, radius_use, radius_use, color.color);
}
void TranslucentBitmap::roundRectFill(int radius, int x1, int y1, int x2, int y2, Graphics::Color color) const {
TransBlender blender;
Bitmap::roundRectFill(radius, x1, y1, x2, y2, transBlendColor(color));
}
void Bitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const {
changeTarget(this, this);
al_draw_filled_pieslice(x, y, radius, ang1 - Util::pi/2, ang2 - ang1, color.color);
}
void TranslucentBitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const {
changeTarget(this, this);
TransBlender blender;
Bitmap::arcFilled(x, y, ang1, ang2, radius, transBlendColor(color));
}
void Bitmap::floodfill( const int x, const int y, const Color color ) const {
/* TODO */
}
void Bitmap::line(const int x1, const int y1, const int x2, const int y2, const Color color) const {
changeTarget(this, this);
al_draw_line(x1, y1, x2, y2, color.color, 1);
}
void TranslucentBitmap::line(const int x1, const int y1, const int x2, const int y2, const Color color) const {
TransBlender blender;
Bitmap::line(x1, y1, x2, y2, transBlendColor(color));
}
void Bitmap::circleFill(int x, int y, int radius, Color color) const {
changeTarget(this, this);
al_draw_filled_circle(x, y, radius, color.color);
}
void Bitmap::circle(int x, int y, int radius, Color color) const {
changeTarget(this, this);
al_draw_circle(x, y, radius, color.color, 1);
}
void Bitmap::circle(int x, int y, int radius, int thickness, Color color) const {
changeTarget(this, this);
al_draw_circle(x, y, radius, color.color, thickness);
}
void Bitmap::rectangle(int x1, int y1, int x2, int y2, Color color ) const {
changeTarget(this, this);
// al_draw_rectangle(x1, y1, x2, y2, color.color, 0);
al_draw_rectangle(x1 + 0.5, y1 + 0.5, x2 - 0.5, y2 - 0.5, color.color, 1);
}
void Bitmap::rectangleFill( int x1, int y1, int x2, int y2, Color color ) const {
changeTarget(this, this);
// al_draw_filled_rectangle(x1 - 0.5, y1 - 0.5, x2 + 0.5, y2 + 0.5, color.color);
al_draw_filled_rectangle(x1, y1, x2 + 1, y2 + 1, color.color);
}
void Bitmap::triangle( int x1, int y1, int x2, int y2, int x3, int y3, Color color ) const {
changeTarget(this, this);
al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, color.color);
}
void Bitmap::polygon( const int * verts, const int nverts, const Color color ) const {
/* TODO */
}
void Bitmap::ellipse( int x, int y, int rx, int ry, Color color ) const {
changeTarget(this, this);
al_draw_ellipse(x, y, rx, ry, color.color, 0);
}
void Bitmap::ellipseFill( int x, int y, int rx, int ry, Color color ) const {
changeTarget(this, this);
al_draw_filled_ellipse(x, y, rx, ry, color.color);
}
void Bitmap::applyTrans(const Color color) const {
TransBlender blender;
changeTarget(this, this);
al_draw_filled_rectangle(0, 0, getWidth(), getHeight(), transBlendColor(color).color);
}
void Bitmap::light(int x, int y, int width, int height, int start_y, int focus_alpha, int edge_alpha, Color focus_color, Color edge_color) const {
/* TODO */
}
void Bitmap::drawCharacter( const int x, const int y, const Color color, const int background, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::save( const std::string & str ) const {
/* TODO */
}
void Bitmap::readLine(std::vector<Color> & line, int y){
/* TODO */
}
void TranslucentBitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where, int flags) const {
changeTarget(this, where);
TransBlender blender;
Util::ReferenceCount<Shader> shader;
if (filter != NULL){
shader = filter->getShader();
}
ALLEGRO_SHADER * a5shader = NULL;
if (shader != NULL){
a5shader = shader->getShader();
}
if (a5shader != NULL){
al_use_shader(a5shader);
filter->setupShader(shader);
}
al_draw_tinted_bitmap(getData()->getBitmap(), getBlendColor().color, x, y, flags);
if (a5shader != NULL){
al_use_shader(NULL);
}
}
void TranslucentBitmap::draw(const int x, const int y, const Bitmap & where) const {
draw(x, y, NULL, where, 0);
}
void LitBitmap::draw(const int x, const int y, const Bitmap & where) const {
draw(x, y, NULL, where, 0);
}
void LitBitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where, int flags) const {
if (filter == NULL){
changeTarget(this, where);
/*
TransBlender blender;
Util::ReferenceCount<Shader> shader;
if (filter != NULL){
shader = filter->getShader();
}
ALLEGRO_SHADER * a5shader = NULL;
if (shader != NULL){
a5shader = shader->getShader();
}
if (a5shader != NULL){
al_set_shader(the_display, a5shader);
al_use_shader(a5shader, true);
}
al_draw_tinted_bitmap(getData()->getBitmap(), getBlendColor().color, x, y, flags);
if (a5shader != NULL){
al_set_shader(the_display, shader_default);
al_use_shader(shader_default, true);
}
*/
MaskedBlender blender;
ALLEGRO_SHADER * shader = shader_lit_sprite->getShader();
float light[4];
Color color = makeColor(globalBlend.red, globalBlend.green, globalBlend.blue);
al_unmap_rgb_f(color.color, &light[0], &light[1], &light[2]);
light[3] = 1;
float intensity = (float) globalBlend.alpha / 255.0;
al_use_shader(shader);
if (!al_set_shader_float_vector("light_color", 4, light, 1)){
/* Well.. thats not good. Did the shader source get messed up? */
}
if (!al_set_shader_float("light_intensity", intensity)){
}
al_draw_bitmap(getData()->getBitmap(), x, y, flags);
al_use_shader(NULL);
} else {
Bitmap temp(getWidth(), getHeight());
temp.fill(MaskColor());
Bitmap::draw(0, 0, filter, temp, 0);
LitBitmap(temp).draw(x, y, NULL, where, flags);
}
}
void LitBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, 0);
// LitBlender blender(makeColorAlpha(globalBlend.red, globalBlend.green, globalBlend.blue, globalBlend.alpha));
// TransBlender blender;
// al_draw_bitmap(getData()->getBitmap(), x, y, 0);
// al_draw_tinted_bitmap(getData()->getBitmap(), al_map_rgba_f(1, 0, 0, 1), x, y, 0);
}
void LitBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL);
}
void LitBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL);
}
void LitBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_VERTICAL);
}
void LitBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_VERTICAL);
}
void LitBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void LitBitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void TranslucentBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, 0);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_VERTICAL);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_VERTICAL);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
draw(x, y, NULL, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, Filter * filter,const Bitmap & where ) const {
draw(x, y, filter, where, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL);
}
void TranslucentBitmap::hLine( const int x1, const int y, const int x2, const Color color ) const {
TransBlender blender;
Bitmap::hLine(x1, y, x2, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::circleFill(int x, int y, int radius, Color color) const {
TransBlender blender;
Bitmap::circleFill(x, y, radius, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::putPixelNormal(int x, int y, Color color) const {
TransBlender blender;
Bitmap::putPixelNormal(x, y, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::rectangle( int x1, int y1, int x2, int y2, Color color ) const {
TransBlender blender;
Bitmap::rectangle(x1, y1, x2, y2, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::rectangleFill(int x1, int y1, int x2, int y2, Color color) const {
TransBlender blender;
Bitmap::rectangleFill(x1, y1, x2, y2, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::ellipse( int x, int y, int rx, int ry, Color color ) const {
TransBlender blender;
Bitmap::ellipse(x, y, rx, ry, doTransBlend(color, globalBlend.alpha));
}
void TranslucentBitmap::ellipseFill( int x, int y, int rx, int ry, Color color ) const {
TransBlender blender;
Bitmap::ellipseFill(x, y, rx, ry, doTransBlend(color, globalBlend.alpha));
}
void Bitmap::setClipRect( int x1, int y1, int x2, int y2 ) const {
/* TODO */
}
void Bitmap::getClipRect(int & x1, int & y1, int & x2, int & y2) const {
/* TODO */
}
int setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
int setGfxModeWindowed( int x, int y ){
return setGraphicsMode(WINDOWED, x, y);
}
int setGfxModeText(){
/* TODO */
return 0;
}
bool Bitmap::getError(){
/* TODO */
return false;
}
void Bitmap::alphaBlender(int source, int dest){
/* TODO */
}
void Bitmap::transBlender(int r, int g, int b, int a){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.type = Translucent;
}
void Bitmap::addBlender(int r, int g, int b, int a){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.type = Add;
}
void Bitmap::differenceBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.type = Difference;
}
void Bitmap::multiplyBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.type = Multiply;
}
/*
void Bitmap::drawingMode(int type){
}
*/
void Bitmap::shutdown(){
/* Make sure the display is set */
if (Screen != NULL){
al_set_target_bitmap(Screen->getData()->getBitmap());
}
al_use_shader(NULL);
shaders.clear();
shader_shadow = NULL;
shader_lit_sprite = NULL;
/*
for (std::vector<ALLEGRO_SHADER*>::iterator it = shaders.begin(); it != shaders.end(); it++){
ALLEGRO_SHADER * shader = *it;
al_destroy_shader(shader);
}
*/
delete Screen;
Screen = NULL;
al_destroy_display(the_display);
the_display = NULL;
/*
delete Scaler;
Scaler = NULL;
delete Buffer;
Buffer = NULL;
*/
}
StretchedBitmap::StretchedBitmap(int width, int height, const Bitmap & parent, Clear clear, QualityFilter filter):
Bitmap(parent, 0, 0, parent.getWidth(), parent.getHeight()),
width(width),
height(height),
where(parent),
filter(filter),
clearKind(clear){
scale_x = (double) parent.getWidth() / width;
scale_y = (double) parent.getHeight() / height;
ALLEGRO_BITMAP * old_target = al_get_target_bitmap();
if (al_get_target_bitmap() != parent.getData()->getBitmap()){
al_set_target_bitmap(parent.getData()->getBitmap());
}
ALLEGRO_TRANSFORM transform;
al_identity_transform(&transform);
if (al_get_current_transform() != NULL){
al_copy_transform(&transform, al_get_current_transform());
}
al_scale_transform(&transform, scale_x, scale_y);
if (al_get_target_bitmap() != getData()->getBitmap()){
al_set_target_bitmap(getData()->getBitmap());
}
al_use_transform(&transform);
if (old_target != al_get_target_bitmap()){
al_set_target_bitmap(old_target);
}
switch (clear){
case NoClear: break;
case FullClear: this->clear();
case Mask: break;
}
/* TODO: handle filter */
}
void StretchedBitmap::start(){
#if 0
ALLEGRO_TRANSFORM transform;
changeTarget(this, this);
al_copy_transform(&transform, al_get_current_transform());
// al_identity_transform(&transform);
// al_scale_transform(&transform, Bitmap::getWidth() / width, Bitmap::getHeight() / height);
al_scale_transform(&transform, scale_x, scale_y);
al_use_transform(&transform);
#endif
}
void StretchedBitmap::finish(){
#if 0
ALLEGRO_TRANSFORM transform;
changeTarget(this, this);
al_copy_transform(&transform, al_get_current_transform());
/* apply the inverse transform */
al_scale_transform(&transform, 1.0/scale_x, 1.0/scale_y);
// al_identity_transform(&transform);
al_use_transform(&transform);
#endif
}
SubTranslucentBitmap::SubTranslucentBitmap(const Bitmap & where, int x, int y, int width, int height, Clear clear):
Bitmap(where, x, y, width, height),
translucent(*this),
clearKind(clear){
switch (clear){
case NoClear: break;
case FullClear: translucent.clear();
case Mask: break;
}
}
void SubTranslucentBitmap::finish(){
}
void SubTranslucentBitmap::start(){
}
void SubTranslucentBitmap::roundRect(int radius, int x1, int y1, int x2, int y2, Color color) const {
translucent.roundRect(radius, x1, y1, x2, y2, color);
}
void SubTranslucentBitmap::roundRectFill(int radius, int x1, int y1, int x2, int y2, Graphics::Color color) const {
translucent.roundRectFill(radius, x1, y1, x2, y2, color);
}
TranslatedBitmap::TranslatedBitmap(int x, int y, const Bitmap & where):
Bitmap(where),
x(x),
y(y){
ALLEGRO_TRANSFORM transform;
changeTarget(this, where);
al_identity_transform(&transform);
if (al_get_current_transform() != NULL){
al_copy_transform(&transform, al_get_current_transform());
}
al_translate_transform(&transform, x, y);
al_use_transform(&transform);
}
void TranslatedBitmap::BlitToScreen() const {
Bitmap::BlitToScreen();
}
TranslatedBitmap::~TranslatedBitmap(){
ALLEGRO_TRANSFORM transform;
al_copy_transform(&transform, al_get_current_transform());
al_translate_transform(&transform, -x, -y);
al_use_transform(&transform);
}
Bitmap * getScreenBuffer(){
return Screen;
}
RestoreState::RestoreState(){
al_store_state(&state, ALLEGRO_STATE_ALL);
}
RestoreState::~RestoreState(){
al_restore_state(&state);
}
Shader::Shader():
shader(NULL){
}
Shader::~Shader(){
if (shader != NULL){
al_destroy_shader(shader);
}
}
Shader::Shader(ALLEGRO_SHADER * shader):
shader(shader){
}
ALLEGRO_SHADER * Shader::getShader(){
return shader;
}
}
static inline bool close(float x, float y){
static float epsilon = 0.001;
return fabs(x - y) < epsilon;
}
static inline bool sameColor(const ALLEGRO_COLOR & color1, const ALLEGRO_COLOR & color2){
// return memcmp(&color1, &color2, sizeof(Graphics::Color)) == 0;
float r1, g1, b1, a1;
float r2, g2, b2, a2;
al_unmap_rgba_f(color1, &r1, &g1, &b1, &a1);
al_unmap_rgba_f(color2, &r2, &g2, &b2, &a2);
return close(r1, r2) &&
close(g1, g2) &&
close(b1, b2) &&
close(a1, a2);
/*
unsigned char r1, g1, b1, a1;
unsigned char r2, g2, b2, a2;
al_unmap_rgba(color1, &r1, &g1, &b1, &a1);
al_unmap_rgba(color2, &r2, &g2, &b2, &a2);
return r1 == r2 &&
g1 == g2 &&
b1 == b2 &&
a1 == a2;
*/
}
static uint32_t quantify(const ALLEGRO_COLOR & color){
unsigned char red, green, blue, alpha;
al_unmap_rgba(color, &red, &green, &blue, &alpha);
return (red << 24) |
(green << 16) |
(blue << 8) |
alpha;
}
bool operator<(const ALLEGRO_COLOR & color1, const ALLEGRO_COLOR & color2){
return quantify(color1) < quantify(color2);
}
bool operator!=(const ALLEGRO_COLOR & color1, const ALLEGRO_COLOR & color2){
return !(color1 == color2);
}
bool operator==(const ALLEGRO_COLOR & color1, const ALLEGRO_COLOR & color2){
return sameColor(color1, color2);
}
diff --git a/src/input/allegro5/touch.cpp b/src/input/allegro5/touch.cpp
index e04ee076..9b07afe8 100644
--- a/src/input/allegro5/touch.cpp
+++ b/src/input/allegro5/touch.cpp
@@ -1,172 +1,216 @@
#ifdef USE_ALLEGRO5
#include "r-tech1/input/touch.h"
#include "r-tech1/pointer.h"
#include "r-tech1/debug.h"
+#include "r-tech1/graphics/bitmap.h"
#include <allegro5/allegro.h>
#include <map>
namespace DeviceInput{
class TouchTrack{
public:
TouchTrack(int id, double x, double y):
id(id),
x(x),
y(y),
last_x(x),
last_y(y){
}
void update(double x, double y){
this->last_x = this->x;
this->last_y = this->y;
this->x = x;
this->y = y;
}
int id;
double x;
double y;
double last_x;
double last_y;
};
class Allegro5Touch: public Touch {
public:
Allegro5Touch();
virtual void poll();
virtual ~Allegro5Touch();
void handleTouch(const Util::ReferenceCount<TouchTrack> & touch, std::map<Key, bool> & buttons, bool press);
void generateEvents(std::map<Key, bool> & new_buttons);
+ void setZone(Key key, int x1, int y1, int x2, int y2){
+ zones[key] = Zone(x1, y1, x2, y2);
+ }
+
bool inZone(Key key, double x, double y);
+ virtual void drawTouchOverlay(const Graphics::Bitmap & bitmap);
+
+ struct Zone{
+ Zone():
+ x1(-1),
+ y1(-1),
+ x2(-1),
+ y2(-1){
+ }
+
+ Zone(int x1, int y1, int x2, int y2):
+ x1(x1),
+ y1(y1),
+ x2(x2),
+ y2(y2){
+ }
+
+ int x1, y1, x2, y2;
+ };
+
protected:
ALLEGRO_EVENT_QUEUE * queue;
std::map<int, Util::ReferenceCount<TouchTrack> > touches;
std::map<Key, bool> buttons;
+ std::map<Key, Zone> zones;
};
Allegro5Touch::Allegro5Touch():
queue(NULL){
if (al_install_touch_input()){
queue = al_create_event_queue();
if (queue != NULL){
al_register_event_source(queue, al_get_touch_input_event_source());
}
}
}
bool Allegro5Touch::inZone(Key key, double x, double y){
- _xdebug << "Check for zone " << key << " in " << x << ", " << y << std::endl;
- switch (key){
- case Up: {
- return
- x >= 0 && x <= 20 &&
- y >= 0 && y <= 20;
- }
- case Down: {
- return
- x >= 0 && x <= 20 &&
- y >= 20 && y <= 40;
- }
- default: {
- return false;
- }
- }
- return false;
+ // _xdebug << "Check for zone " << key << " in " << x << ", " << y << std::endl;
+ const Zone & zone = zones[key];
+ return x >= zone.x1 && x <= zone.x2 &&
+ y >= zone.y1 && y <= zone.y2;
+}
+
+static std::vector<Touch::Key> allKeys(){
+ std::vector<Touch::Key> keys;
+ keys.push_back(Touch::Up);
+ keys.push_back(Touch::Down);
+ keys.push_back(Touch::Left);
+ keys.push_back(Touch::Right);
+ keys.push_back(Touch::Button1);
+ keys.push_back(Touch::Button2);
+ keys.push_back(Touch::Button3);
+ keys.push_back(Touch::Button4);
+ keys.push_back(Touch::Button5);
+ keys.push_back(Touch::Button6);
+ keys.push_back(Touch::Quit);
+ keys.push_back(Touch::Start);
+ return keys;
}
void Allegro5Touch::handleTouch(const Util::ReferenceCount<TouchTrack> & touch, std::map<Key, bool> & new_buttons, bool press){
- if (inZone(Up, touch->x, touch->y)){
- new_buttons[Up] = press;
- }
- if (inZone(Down, touch->x, touch->y)){
- new_buttons[Down] = press;
+ std::vector<Key> all = allKeys();
+ for (std::vector<Key>::iterator it = all.begin(); it != all.end(); it++){
+ if (inZone(*it, touch->x, touch->y)){
+ new_buttons[*it] = press;
+ }
}
}
/* Generate a 'pressed' event if the current state was not pressd and the new state is pressed.
* Similarly, generate a 'release' event if the current state was pressed and the new state was not pressed
*
*/
void Allegro5Touch::generateEvents(std::map<Key, bool> & new_buttons){
- if (buttons[Up] ^ new_buttons[Up]){
- events.push_back(Event(Up, new_buttons[Up]));
+ std::vector<Key> all = allKeys();
+ for (std::vector<Key>::iterator it = all.begin(); it != all.end(); it++){
+ Key key = *it;
+ if (buttons[key] ^ new_buttons[key]){
+ events.push_back(Event(key, new_buttons[key]));
+ }
}
}
void Allegro5Touch::poll(){
if (queue == NULL){
return;
}
events.clear();
std::map<Key, bool> new_buttons;
ALLEGRO_EVENT event;
while (al_get_next_event(queue, &event)){
switch (event.type){
case ALLEGRO_EVENT_TOUCH_BEGIN: {
// Global::debug(0) << "Touch begin id (" << event.touch.id << ") x (" << (double) event.touch.x << ") y (" << (double) event.touch.y << ")" << std::endl;
int id = event.touch.id;
double x = event.touch.x;
double y = event.touch.y;
touches[id] = Util::ReferenceCount<TouchTrack>(new TouchTrack(id, x, y));
handleTouch(touches[id], new_buttons, true);
break;
}
case ALLEGRO_EVENT_TOUCH_END: {
int id = event.touch.id;
double x = event.touch.x;
double y = event.touch.y;
handleTouch(touches[id], new_buttons, false);
touches[id] = NULL;
// Global::debug(0) << "Touch end id (" << event.touch.id << ") x (" << (double) event.touch.x << ") y (" << (double) event.touch.y << ")" << std::endl;
break;
}
case ALLEGRO_EVENT_TOUCH_MOVE: {
int id = event.touch.id;
double x = event.touch.x;
double y = event.touch.y;
if (touches[id] != NULL){
touches[id]->update(x, y);
} else {
touches[id] = Util::ReferenceCount<TouchTrack>(new TouchTrack(id, x, y));
}
handleTouch(touches[id], new_buttons, true);
// Global::debug(0) << "Touch move id (" << event.touch.id << ") x (" << (double) event.touch.x << ") y (" << (double) event.touch.y << ")" << std::endl;
break;
}
case ALLEGRO_EVENT_TOUCH_CANCEL: {
// Global::debug(0) << "Touch cancel id (" << event.touch.id << ") x (" << (double) event.touch.x << ") y (" << (double) event.touch.y << ")" << std::endl;
int id = event.touch.id;
handleTouch(touches[id], new_buttons, false);
touches[id] = NULL;
break;
}
}
}
generateEvents(new_buttons);
}
+
+void Allegro5Touch::drawTouchOverlay(const Graphics::Bitmap & bitmap){
+ Graphics::TranslucentBitmap translucent = bitmap.translucent(0, 0, 0, 96);
+ for (std::map<Key, Zone>::iterator it = zones.begin(); it != zones.end(); it++){
+ Key key = it->first;
+ Zone zone = it->second;
+
+ translucent.rectangleFill(zone.x1, zone.y1, zone.x2, zone.y2, Graphics::makeColor(128, 128, 200));
+ }
+}
Allegro5Touch::~Allegro5Touch(){
al_destroy_event_queue(queue);
queue = NULL;
}
Util::ReferenceCount<Touch> getTouchDevice(){
return Util::ReferenceCount<Touch>(new Allegro5Touch());
}
}
#endif
diff --git a/src/input/input-manager.cpp b/src/input/input-manager.cpp
index ba9d58f4..d7852976 100644
--- a/src/input/input-manager.cpp
+++ b/src/input/input-manager.cpp
@@ -1,161 +1,167 @@
#include "r-tech1/input/input-manager.h"
#include "r-tech1/configuration.h"
#include "r-tech1/input/joystick.h"
#include "r-tech1/events.h"
#include "r-tech1/debug.h"
#include <stdlib.h>
#include <vector>
using namespace std;
InputManager * InputManager::manager = 0;
InputManager::InputManager():
capture(0){
manager = this;
if (Configuration::isJoystickEnabled()){
installJoysticks();
}
touch = DeviceInput::getTouchDevice();
}
+const Util::ReferenceCount<DeviceInput::Touch> & InputManager::getTouch(){
+ if (manager != NULL){
+ return manager->touch;
+ }
+}
+
void InputManager::installJoysticks(){
joysticks.clear();
for (int i = 0; i < Joystick::numberOfJoysticks(); i++){
joysticks[i] = Joystick::create(i);
}
}
const std::map<int, Util::ReferenceCount<Joystick> > & InputManager::getJoysticks(){
if (manager != NULL){
return manager->joysticks;
}
Global::debug(0) << "*BUG* Input manager not set up" << endl;
exit(0);
}
#ifdef PS3
#include <io/pad.h>
extern "C" int SDL_JoystickInit();
extern "C" int SDL_JoystickQuit();
#endif
static bool needJoystickUpdate(){
#ifdef PS3
padInfo pad;
if (ioPadGetInfo(&pad) == 0){
/* re-initialize the joystick stuff if we have a different
* number of joysticks according to lv2
*/
if (pad.connected != (unsigned) SDL_NumJoysticks()){
SDL_JoystickQuit();
SDL_JoystickInit();
return true;
}
}
#endif
return false;
}
void InputManager::checkJoysticks(){
if (needJoystickUpdate()){
installJoysticks();
}
}
InputManager::~InputManager(){
}
void InputManager::deferResizeEvents(bool defer){
if (manager != NULL){
manager->eventManager.deferResizeEvents(defer);
}
}
bool InputManager::anyInput(){
if (manager == 0){
Global::debug(0) << "*BUG* Input manager not set up" << endl;
exit(0);
}
return manager->_anyInput();
}
bool InputManager::_anyInput(){
if (keyboard.keypressed()){
return true;
}
for (map<int, Util::ReferenceCount<Joystick> >::iterator it = joysticks.begin(); it != joysticks.end(); it++){
Util::ReferenceCount<Joystick> joystick = it->second;
if (joystick != NULL){
return joystick->pressed();
}
}
return false;
}
void InputManager::waitForClear(){
manager->keyboard.clear();
while (anyInput()){
poll();
Util::rest(1);
}
}
void InputManager::waitForKeys(int key1, int key2, const InputSource & source){
InputMap<int> wait;
wait.set(key1, 0, false, 1);
wait.set(key2, 0, false, 1);
InputManager::waitForRelease(wait, source, 1);
InputManager::waitForPress(wait, source, 1);
InputManager::waitForRelease(wait, source, 1);
}
void InputManager::waitForKeys(int key, const InputSource & source){
InputMap<int> wait;
wait.set(key, 0, false, 1);
InputManager::waitForRelease(wait, source, 1);
InputManager::waitForPress(wait, source, 1);
InputManager::waitForRelease(wait, source, 1);
}
void InputManager::poll(){
if (manager == 0){
Global::debug(0) << "*BUG* Input manager not set up" << endl;
exit(0);
}
return manager->_poll();
}
int InputManager::readKey(){
return manager->_readKey();
}
int InputManager::_readKey(){
std::vector<int> keys;
do{
keyboard.readKeys(keys);
if (keys.size() == 0){
Util::rest(1);
poll();
}
} while (keys.size() == 0);
return keys.front();
}
std::vector<DeviceInput::Touch::Event> InputManager::getTouchEvents(){
if (touch != NULL){
return touch->getEvents();
}
}
void InputManager::_poll(){
#ifdef PS3
checkJoysticks();
#endif
touch->poll();
eventManager.run(keyboard, joysticks);
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:31 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70962
Default Alt Text
(109 KB)

Event Timeline