Merge pull request #731 from Botje/android-tinygl

Basic support for Android
This commit is contained in:
Paweł Kołodziejski 2013-07-06 22:52:13 -07:00
commit 1f3ad19a38
34 changed files with 1659 additions and 552 deletions

View File

@ -133,7 +133,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
_ar_correction(true),
_show_mouse(false),
_show_overlay(false),
_virt_arrowkeys_pressed(false),
_virtcontrols_on(false),
_enable_zoning(false),
_mixer(0),
_shake_offset(0),
@ -149,7 +149,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
_touchpad_scale(66),
_dpad_scale(4),
_fingersDown(0),
_trackball_scale(2) {
_trackball_scale(2)
{
_fsFactory = new POSIXFilesystemFactory();
@ -347,7 +348,7 @@ void OSystem_Android::initBackend() {
_main_thread = pthread_self();
ConfMan.registerDefault("fullscreen", true);
ConfMan.set("fullscreen", "true");
ConfMan.registerDefault("aspect_ratio", true);
ConfMan.setInt("autosave_period", 0);
@ -409,6 +410,7 @@ bool OSystem_Android::hasFeature(Feature f) {
f == kFeatureAspectRatioCorrection ||
f == kFeatureCursorPalette ||
f == kFeatureVirtualKeyboard ||
f == kFeatureVirtControls ||
#ifdef USE_OPENGL
f == kFeatureOpenGL ||
#endif
@ -431,6 +433,9 @@ void OSystem_Android::setFeatureState(Feature f, bool enable) {
_virtkeybd_on = enable;
showVirtualKeyboard(enable);
break;
case kFeatureVirtControls:
_virtcontrols_on = enable;
break;
case kFeatureCursorPalette:
_use_mouse_palette = enable;
if (!enable)
@ -449,6 +454,8 @@ bool OSystem_Android::getFeatureState(Feature f) {
return _ar_correction;
case kFeatureVirtualKeyboard:
return _virtkeybd_on;
case kFeatureVirtControls:
return _virtcontrols_on;
case kFeatureCursorPalette:
return _use_mouse_palette;
default:

View File

@ -35,7 +35,9 @@
#include "backends/plugins/posix/posix-provider.h"
#include "backends/fs/posix/posix-fs-factory.h"
#include "backends/platform/android/events.h"
#include "backends/platform/android/texture.h"
#include "backends/platform/android/touchcontrols.h"
#include <pthread.h>
@ -104,7 +106,7 @@ protected:
};
#endif
class OSystem_Android : public EventsBaseBackend, public PaletteManager {
class OSystem_Android : public EventsBaseBackend, public PaletteManager, public KeyReceiver {
private:
// passed from the dark side
int _audio_sample_rate;
@ -140,7 +142,7 @@ private:
bool _show_mouse;
bool _use_mouse_palette;
int _virt_arrowkeys_pressed;
bool _virtcontrols_on;
int _graphicsMode;
bool _fullscreen;
@ -224,6 +226,7 @@ public:
public:
void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
void keyPress(const Common::KeyCode keycode, const KeyReceiver::KeyPressType type);
private:
Common::Queue<Common::Event> _event_queue;
@ -245,10 +248,9 @@ private:
void updateEventScale();
void disableCursorPalette();
void updateVirtArrowKeys(int keys);
int getTouchArea(int x, int y);
int checkVirtArrowKeys(int action, int x, int y);
void checkVirtArrowKeys(int pointer, int action, int x0, int y0, int x1, int y1);
TouchControls _touchControls;
void drawVirtControls();
protected:
// PaletteManager API
@ -310,7 +312,10 @@ public:
// ResidualVM specific method
virtual void launcherInitSize(uint w, uint h);
bool lockMouse(bool lock);
Graphics::PixelBuffer setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d);
Graphics::PixelBuffer setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d) {
return setupScreen(screenW, screenH, fullscreen, accel3d, true);
}
Graphics::PixelBuffer setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d, bool isGame);
};
#endif

View File

@ -23,6 +23,7 @@ PATH_DIST = $(srcdir)/dists/android
PATH_RESOURCES = $(PATH_DIST)/res
PORT_DISTFILES = $(PATH_DIST)/README.Android
DIST_ANDROID_CONTROLS = $(PATH_DIST)/assets/arrows.tga
RESOURCES = \
$(PATH_RESOURCES)/values/strings.xml \
@ -47,13 +48,7 @@ APKBUILDER = $(ANDROID_SDK)/tools/apkbuilder
JAVAC ?= javac
JAVACFLAGS = -source 1.5 -target 1.5
# This is a bit silly. I want to compile against the 2.1 android.jar,
# to make the compiler check that I don't use something that requires
# a newer Android. However, in order to use android:installLocation,
# we need to give aapt a version >=8 android.jar - even though the
# result will work ok on 2.0+.
ANDROID_JAR = $(ANDROID_SDK)/platforms/android-7/android.jar
ANDROID_JAR8 = $(ANDROID_SDK)/platforms/android-8/android.jar
ANDROID_JAR = $(ANDROID_SDK)/platforms/android-8/android.jar
PATH_BUILD = build.tmp
PATH_BUILD_ASSETS = $(PATH_BUILD)/assets
@ -92,9 +87,9 @@ $(FILE_MANIFEST): $(FILE_MANIFEST_SRC)
@$(MKDIR) -p $(@D)
sed "s/@ANDROID_VERSIONCODE@/$(ANDROID_VERSIONCODE)/" < $< > $@
$(SRC_GEN): $(FILE_MANIFEST) $(filter %.xml,$(RESOURCES)) $(ANDROID_JAR8)
$(SRC_GEN): $(FILE_MANIFEST) $(filter %.xml,$(RESOURCES)) $(ANDROID_JAR)
@$(MKDIR) -p $(PATH_GEN_TOP)
$(AAPT) package -m -J $(PATH_GEN_TOP) -M $< -S $(PATH_RESOURCES) -I $(ANDROID_JAR8)
$(AAPT) package -m -J $(PATH_GEN_TOP) -M $< -S $(PATH_RESOURCES) -I $(ANDROID_JAR)
$(PATH_CLASSES_MAIN)/%.class: $(PATH_GEN)/%.java $(SRC_GEN)
@$(MKDIR) -p $(@D)
@ -127,9 +122,9 @@ $(PATH_STAGE_PREFIX).%/res/drawable/residualvm.png: $(PATH_RESOURCES)/drawable/r
@$(MKDIR) -p $(@D)
$(CP) $< $@
$(FILE_RESOURCES_MAIN): $(FILE_MANIFEST) $(RESOURCES) $(ANDROID_JAR8) $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA)
$(FILE_RESOURCES_MAIN): $(FILE_MANIFEST) $(RESOURCES) $(ANDROID_JAR) $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_ANDROID_CONTROLS)
$(INSTALL) -d $(PATH_BUILD_ASSETS)
$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(PATH_BUILD_ASSETS)/
$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_ANDROID_CONTROLS) $(PATH_BUILD_ASSETS)/
work_dir=`pwd`; \
for i in $(PATH_BUILD_ASSETS)/*.zip; do \
echo "recompress $$i"; \
@ -141,25 +136,21 @@ $(FILE_RESOURCES_MAIN): $(FILE_MANIFEST) $(RESOURCES) $(ANDROID_JAR8) $(DIST_FIL
zip -r ../`basename $$i` *; \
done
@$(RM) -rf $(PATH_BUILD_ASSETS)/tmp
$(AAPT) package -f -0 zip -M $< -S $(PATH_RESOURCES) -A $(PATH_BUILD_ASSETS) -I $(ANDROID_JAR8) -F $@
$(AAPT) package -f -0 "" -M $< -S $(PATH_RESOURCES) -A $(PATH_BUILD_ASSETS) -I $(ANDROID_JAR) -F $@
$(PATH_BUILD)/%/$(FILE_RESOURCES): $(PATH_BUILD)/%/AndroidManifest.xml $(PATH_STAGE_PREFIX).%/res/values/strings.xml $(PATH_STAGE_PREFIX).%/res/drawable/residualvm.png plugins/lib%.so $(ANDROID_JAR8)
$(AAPT) package -f -M $< -S $(PATH_STAGE_PREFIX).$*/res -I $(ANDROID_JAR8) -F $@
$(PATH_BUILD)/%/$(FILE_RESOURCES): $(PATH_BUILD)/%/AndroidManifest.xml $(PATH_STAGE_PREFIX).%/res/values/strings.xml $(PATH_STAGE_PREFIX).%/res/drawable/residualvm.png plugins/lib%.so $(ANDROID_JAR)
$(AAPT) package -f -M $< -S $(PATH_STAGE_PREFIX).$*/res -I $(ANDROID_JAR) -F $@
# Package installer won't delete old libresidualvm.so on upgrade so
# replace it with a zero size file
$(APK_MAIN): $(EXECUTABLE) $(FILE_RESOURCES_MAIN) $(FILE_DEX)
$(INSTALL) -d $(PATH_STAGE_MAIN)/common/lib/armeabi
touch $(PATH_STAGE_MAIN)/common/lib/armeabi/libresidualvm.so
$(INSTALL) -d $(PATH_STAGE_MAIN)/common/mylib/armeabi
$(INSTALL) -c -m 644 libresidualvm.so $(PATH_STAGE_MAIN)/common/mylib/armeabi/
$(STRIP) $(PATH_STAGE_MAIN)/common/mylib/armeabi/libresidualvm.so
$(INSTALL) -c -m 644 libresidualvm.so $(PATH_STAGE_MAIN)/common/lib/armeabi/
$(STRIP) $(PATH_STAGE_MAIN)/common/lib/armeabi/libresidualvm.so
$(APKBUILDER) $@ -z $(FILE_RESOURCES_MAIN) -f $(FILE_DEX) -rf $(PATH_STAGE_MAIN)/common || { $(RM) $@; exit 1; }
residualvm-engine-%.apk: plugins/lib%.so $(PATH_BUILD)/%/$(FILE_RESOURCES) $(FILE_DEX_PLUGIN)
$(INSTALL) -d $(PATH_STAGE_PREFIX).$*/apk/mylib/armeabi/
$(INSTALL) -c -m 644 plugins/lib$*.so $(PATH_STAGE_PREFIX).$*/apk/mylib/armeabi/
$(STRIP) $(PATH_STAGE_PREFIX).$*/apk/mylib/armeabi/lib$*.so
$(INSTALL) -d $(PATH_STAGE_PREFIX).$*/apk/lib/armeabi/
$(INSTALL) -c -m 644 plugins/lib$*.so $(PATH_STAGE_PREFIX).$*/apk/lib/armeabi/
$(STRIP) $(PATH_STAGE_PREFIX).$*/apk/lib/armeabi/lib$*.so
$(APKBUILDER) $@ -z $(PATH_BUILD)/$*/$(FILE_RESOURCES) -f $(FILE_DEX_PLUGIN) -rf $(PATH_STAGE_PREFIX).$*/apk || { $(RM) $@; exit 1; }
all: $(APK_MAIN) $(APK_PLUGINS)

View File

@ -313,6 +313,7 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) :
assert(FID_descriptor);
_fd = env->GetIntField(javafd, FID_descriptor);
seek(0, SEEK_SET);
}
AssetFdReadStream::~AssetFdReadStream() {

View File

@ -39,180 +39,10 @@
// for the Android port
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
#include "common/events.h"
#include "backends/platform/android/android.h"
#include "backends/platform/android/events.h"
#include "backends/platform/android/jni.h"
// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java
// event type
enum {
JE_SYS_KEY = 0,
JE_KEY = 1,
JE_DPAD = 2,
JE_DOWN = 3,
JE_SCROLL = 4,
JE_TAP = 5,
JE_DOUBLE_TAP = 6,
JE_MULTI = 7,
JE_BALL = 8,
JE_TOUCH = 9,
JE_LONG = 10,
JE_FLING = 11,
JE_QUIT = 0x1000
};
// action type
enum {
JACTION_DOWN = 0,
JACTION_UP = 1,
JACTION_MULTIPLE = 2,
JACTION_POINTER_DOWN = 5,
JACTION_POINTER_UP = 6
};
// system keys
enum {
JKEYCODE_SOFT_RIGHT = 2,
JKEYCODE_HOME = 3,
JKEYCODE_BACK = 4,
JKEYCODE_CALL = 5,
JKEYCODE_ENDCALL = 6,
JKEYCODE_VOLUME_UP = 24,
JKEYCODE_VOLUME_DOWN = 25,
JKEYCODE_POWER = 26,
JKEYCODE_CAMERA = 27,
JKEYCODE_HEADSETHOOK = 79,
JKEYCODE_FOCUS = 80,
JKEYCODE_MENU = 82,
JKEYCODE_SEARCH = 84,
JKEYCODE_MUTE = 91,
JKEYCODE_MEDIA_PLAY_PAUSE = 85,
JKEYCODE_MEDIA_STOP = 86,
JKEYCODE_MEDIA_NEXT = 87,
JKEYCODE_MEDIA_PREVIOUS = 88,
JKEYCODE_MEDIA_REWIND = 89,
JKEYCODE_MEDIA_FAST_FORWARD = 90
};
// five-way navigation control
enum {
JKEYCODE_DPAD_UP = 19,
JKEYCODE_DPAD_DOWN = 20,
JKEYCODE_DPAD_LEFT = 21,
JKEYCODE_DPAD_RIGHT = 22,
JKEYCODE_DPAD_CENTER = 23
};
// meta modifier
enum {
JMETA_SHIFT = 0x01,
JMETA_ALT = 0x02,
JMETA_SYM = 0x04,
JMETA_CTRL = 0x1000
};
// map android key codes to our kbd codes
static const Common::KeyCode jkeymap[] = {
Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN
Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT
Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_HOME
Common::KEYCODE_INVALID, // KEYCODE_BACK
Common::KEYCODE_INVALID, // KEYCODE_CALL
Common::KEYCODE_INVALID, // KEYCODE_ENDCALL
Common::KEYCODE_0, // KEYCODE_0
Common::KEYCODE_1, // KEYCODE_1
Common::KEYCODE_2, // KEYCODE_2
Common::KEYCODE_3, // KEYCODE_3
Common::KEYCODE_4, // KEYCODE_4
Common::KEYCODE_5, // KEYCODE_5
Common::KEYCODE_6, // KEYCODE_6
Common::KEYCODE_7, // KEYCODE_7
Common::KEYCODE_8, // KEYCODE_8
Common::KEYCODE_9, // KEYCODE_9
Common::KEYCODE_ASTERISK, // KEYCODE_STAR
Common::KEYCODE_HASH, // KEYCODE_POUND
Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP
Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN
Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN
Common::KEYCODE_INVALID, // KEYCODE_POWER
Common::KEYCODE_INVALID, // KEYCODE_CAMERA
Common::KEYCODE_INVALID, // KEYCODE_CLEAR
Common::KEYCODE_a, // KEYCODE_A
Common::KEYCODE_b, // KEYCODE_B
Common::KEYCODE_c, // KEYCODE_C
Common::KEYCODE_d, // KEYCODE_D
Common::KEYCODE_e, // KEYCODE_E
Common::KEYCODE_f, // KEYCODE_F
Common::KEYCODE_g, // KEYCODE_G
Common::KEYCODE_h, // KEYCODE_H
Common::KEYCODE_i, // KEYCODE_I
Common::KEYCODE_j, // KEYCODE_J
Common::KEYCODE_k, // KEYCODE_K
Common::KEYCODE_l, // KEYCODE_L
Common::KEYCODE_m, // KEYCODE_M
Common::KEYCODE_n, // KEYCODE_N
Common::KEYCODE_o, // KEYCODE_O
Common::KEYCODE_p, // KEYCODE_P
Common::KEYCODE_q, // KEYCODE_Q
Common::KEYCODE_r, // KEYCODE_R
Common::KEYCODE_s, // KEYCODE_S
Common::KEYCODE_t, // KEYCODE_T
Common::KEYCODE_u, // KEYCODE_U
Common::KEYCODE_v, // KEYCODE_V
Common::KEYCODE_w, // KEYCODE_W
Common::KEYCODE_x, // KEYCODE_X
Common::KEYCODE_y, // KEYCODE_Y
Common::KEYCODE_z, // KEYCODE_Z
Common::KEYCODE_COMMA, // KEYCODE_COMMA
Common::KEYCODE_PERIOD, // KEYCODE_PERIOD
Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT
Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT
Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT
Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT
Common::KEYCODE_TAB, // KEYCODE_TAB
Common::KEYCODE_SPACE, // KEYCODE_SPACE
Common::KEYCODE_LCTRL, // KEYCODE_SYM
Common::KEYCODE_INVALID, // KEYCODE_EXPLORER
Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE
Common::KEYCODE_RETURN, // KEYCODE_ENTER
Common::KEYCODE_BACKSPACE, // KEYCODE_DEL
Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE
Common::KEYCODE_MINUS, // KEYCODE_MINUS
Common::KEYCODE_EQUALS, // KEYCODE_EQUALS
Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET
Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET
Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH
Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON
Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE
Common::KEYCODE_SLASH, // KEYCODE_SLASH
Common::KEYCODE_AT, // KEYCODE_AT
Common::KEYCODE_INVALID, // KEYCODE_NUM
Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK
Common::KEYCODE_INVALID, // KEYCODE_FOCUS
Common::KEYCODE_PLUS, // KEYCODE_PLUS
Common::KEYCODE_INVALID, // KEYCODE_MENU
Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION
Common::KEYCODE_INVALID, // KEYCODE_SEARCH
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD
Common::KEYCODE_INVALID, // KEYCODE_MUTE
Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP
Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN
};
// floating point. use sparingly
template<class T>
static inline T scalef(T in, float numerator, float denominator) {
@ -311,108 +141,6 @@ void OSystem_Android::updateEventScale() {
_eventScaleX = 100 * 640 / tex->width();
}
enum TouchArea {
kTouchAreaCenter = 1,
kTouchAreaTop = 2,
kTouchAreaBottom = 4,
kTouchAreaLeft = 8,
kTouchAreaRight = 16
};
enum VirtArrowKey {
kVirtArrowKeyUp = 1,
kVirtArrowKeyDown = 2,
kVirtArrowKeyLeft = 4,
kVirtArrowKeyRight = 8,
kVirtArrowKeyRun = 16
};
void OSystem_Android::updateVirtArrowKeys(int keys) {
Common::Event e;
#if 0
if (keys != _virt_arrowkeys_pressed) {
debug("keys: %d%d%d%d%d / %d%d%d%d%d",
(_virt_arrowkeys_pressed >> 0) & 1, (_virt_arrowkeys_pressed >> 1) & 1,
(_virt_arrowkeys_pressed >> 2) & 1, (_virt_arrowkeys_pressed >> 3) & 1,
(_virt_arrowkeys_pressed >> 4) & 1,
(keys >> 0) & 1, (keys >> 1) & 1,
(keys >> 2) & 1, (keys >> 3) & 1,
(keys >> 4) & 1);
}
#endif
Common::KeyCode keymap[] = {
Common::KEYCODE_UP, Common::KEYCODE_DOWN,
Common::KEYCODE_LEFT, Common::KEYCODE_RIGHT,
Common::KEYCODE_LSHIFT
};
lockMutex(_event_queue_lock);
for (int i = 0; i < 5; ++i) {
int mask = (1 << i);
if ((_virt_arrowkeys_pressed & mask) && !(keys & mask)) {
e.type = Common::EVENT_KEYUP;
e.kbd.keycode = keymap[i];
_event_queue.push(e);
} else if (!(_virt_arrowkeys_pressed & mask) && (keys & mask)) {
e.type = Common::EVENT_KEYDOWN;
e.kbd.keycode = keymap[i];
_event_queue.push(e);
}
}
unlockMutex(_event_queue_lock);
_virt_arrowkeys_pressed = keys;
}
int OSystem_Android::getTouchArea(int x, int y) {
int xScaled = x * 100 / _egl_surface_width;
int yScaled = y * 100 / _egl_surface_height;
if (xScaled >= 35 && xScaled <= 65 && yScaled >= 35 && yScaled <= 65)
return kTouchAreaCenter;
int res = 0;
if (xScaled >= 0 && xScaled <= 20)
res |= kTouchAreaLeft;
else if (xScaled >= 80 && xScaled <= 100)
res |= kTouchAreaRight;
if (yScaled >= 0 && yScaled <= 20)
res |= kTouchAreaTop;
else if (yScaled >= 80 && yScaled <= 100)
res |= kTouchAreaBottom;
return res;
}
int OSystem_Android::checkVirtArrowKeys(int action, int x, int y) {
int res = 0;
int touchArea = getTouchArea(x, y);
if (touchArea & kTouchAreaLeft) {
res |= kVirtArrowKeyLeft;
} else if (touchArea & kTouchAreaRight) {
res |= kVirtArrowKeyRight;
}
if (touchArea & kTouchAreaTop) {
res |= kVirtArrowKeyUp;
} else if (touchArea & kTouchAreaBottom) {
res |= kVirtArrowKeyDown;
}
return res;
}
void OSystem_Android::checkVirtArrowKeys(int pointer, int action, int x0, int y0, int x1, int y1) {
int virtArrowkey = _virt_arrowkeys_pressed & kVirtArrowKeyRun;
if (!(action == JACTION_POINTER_UP && pointer == 0))
virtArrowkey |= checkVirtArrowKeys(action, x0, y0);
if (!(action == JACTION_POINTER_UP && pointer == 1) && x1 != -1)
virtArrowkey |= checkVirtArrowKeys(action, x1, y1);
updateVirtArrowKeys(virtArrowkey);
}
void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
int arg4, int arg5, int arg6) {
Common::Event e;
@ -709,46 +437,13 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
return;
case JE_LONG:
if (!_show_mouse &&
getTouchArea(arg1, arg2) == kTouchAreaCenter)
{
e.kbd.keycode = Common::KEYCODE_i;
e.kbd.ascii = 'i';
lockMutex(_event_queue_lock);
e.type = Common::EVENT_KEYDOWN;
_event_queue.push(e);
e.type = Common::EVENT_KEYUP;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
break;
case JE_FLING:
if (!_show_mouse &&
(getTouchArea(arg1, arg2) == kTouchAreaCenter ||
getTouchArea(arg3, arg4) == kTouchAreaCenter))
{
e.kbd.keycode = Common::KEYCODE_PERIOD;
e.kbd.ascii = '.';
lockMutex(_event_queue_lock);
e.type = Common::EVENT_KEYDOWN;
_event_queue.push(e);
e.type = Common::EVENT_KEYUP;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
break;
case JE_TAP:
if (_fingersDown > 0) {
_fingersDown = 0;
return;
}
if (_show_mouse) {
if (!_virtcontrols_on) {
e.type = Common::EVENT_MOUSEMOVE;
if (_touchpad_mode) {
@ -789,17 +484,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
unlockMutex(_event_queue_lock);
} else {
if (getTouchArea(arg1, arg2) == kTouchAreaCenter) {
e.kbd.keycode = Common::KEYCODE_RETURN;
e.kbd.ascii = Common::ASCII_RETURN;
lockMutex(_event_queue_lock);
e.type = Common::EVENT_KEYDOWN;
_event_queue.push(e);
e.type = Common::EVENT_KEYUP;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
keyPress(Common::KEYCODE_RETURN, KeyReceiver::PRESS);
}
return;
@ -828,7 +513,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
dptype = Common::EVENT_LBUTTONUP;
break;
// held and moved
case JACTION_MULTIPLE:
case JACTION_MOVE:
if (_touch_pt_dt.x == -1 && _touch_pt_dt.y == -1) {
_touch_pt_dt.x = arg1;
_touch_pt_dt.y = arg2;
@ -858,53 +543,34 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
unlockMutex(_event_queue_lock);
}
} else {
int touchArea = getTouchArea(arg1, arg2);
if (touchArea && touchArea != kTouchAreaCenter) {
updateVirtArrowKeys(_virt_arrowkeys_pressed | kVirtArrowKeyRun);
} else if (touchArea == kTouchAreaCenter) {
e.kbd.keycode = Common::KEYCODE_u;
e.kbd.ascii = 'u';
lockMutex(_event_queue_lock);
e.type = Common::EVENT_KEYDOWN;
_event_queue.push(e);
e.type = Common::EVENT_KEYUP;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
keyPress(Common::KEYCODE_u, KeyReceiver::PRESS);
}
return;
case JE_TOUCH:
case JE_MULTI:
{
if (!_show_mouse) {
_touchControls.update(arg1, arg2, arg3, arg4);
return;
}
switch (arg2) {
case JACTION_DOWN:
case JACTION_MULTIPLE:
if (!_show_mouse) {
checkVirtArrowKeys(arg1, arg2, arg3, arg4, arg5, arg6);
}
return;
case JACTION_UP:
updateVirtArrowKeys(0);
return;
case JACTION_POINTER_DOWN:
if (arg1 > _fingersDown)
_fingersDown = arg1;
/* no break */
if (!_show_mouse) {
checkVirtArrowKeys(arg1, arg2, arg3, arg4, arg5, arg6);
}
case JACTION_DOWN:
case JACTION_MOVE:
return;
case JACTION_POINTER_UP:
if (arg1 != _fingersDown)
return;
case JACTION_UP:
case JACTION_POINTER_UP: {
if (_show_mouse) {
if (arg1 != _fingersDown)
return;
Common::EventType up;
switch (_fingersDown) {
@ -935,13 +601,13 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
_queuedEventTime = getMillis() + kQueuedInputEventDelay;
unlockMutex(_event_queue_lock);
} else {
checkVirtArrowKeys(arg1, arg2, arg3, arg4, arg5, arg6);
}
return;
}
}
return;
}
case JE_BALL:
e.mouse = getEventManager()->getMousePos();
@ -953,7 +619,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
case JACTION_UP:
e.type = Common::EVENT_LBUTTONUP;
break;
case JACTION_MULTIPLE:
case JACTION_MOVE:
e.type = Common::EVENT_MOUSEMOVE;
// already multiplied by 100
@ -1052,4 +718,19 @@ bool OSystem_Android::pollEvent(Common::Event &event) {
return true;
}
void OSystem_Android::keyPress(const Common::KeyCode keycode, const KeyReceiver::KeyPressType type) {
Common::Event e;
e.kbd.keycode = keycode;
lockMutex(_event_queue_lock);
if (type == KeyReceiver::DOWN || type == KeyReceiver::PRESS) {
e.type = Common::EVENT_KEYDOWN;
_event_queue.push(e);
}
if (type == KeyReceiver::UP || type == KeyReceiver::PRESS) {
e.type = Common::EVENT_KEYUP;
_event_queue.push(e);
}
unlockMutex(_event_queue_lock);
}
#endif

View File

@ -0,0 +1,204 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ANDROID_EVENTS_H
#define ANDROID_EVENTS_H
#include "common/events.h"
class KeyReceiver {
public:
enum KeyPressType { DOWN, UP, PRESS };
virtual void keyPress(const Common::KeyCode code, const KeyPressType type = PRESS) = 0;
virtual ~KeyReceiver() {};
};
// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java
// event type
enum {
JE_SYS_KEY = 0,
JE_KEY = 1,
JE_DPAD = 2,
JE_DOWN = 3,
JE_SCROLL = 4,
JE_TAP = 5,
JE_DOUBLE_TAP = 6,
JE_MULTI = 7,
JE_BALL = 8,
JE_TOUCH = 9,
JE_LONG = 10,
JE_FLING = 11,
JE_QUIT = 0x1000
};
// action type
enum {
JACTION_DOWN = 0,
JACTION_UP = 1,
JACTION_MOVE = 2,
JACTION_POINTER_DOWN = 5,
JACTION_POINTER_UP = 6
};
// system keys
enum {
JKEYCODE_SOFT_RIGHT = 2,
JKEYCODE_HOME = 3,
JKEYCODE_BACK = 4,
JKEYCODE_CALL = 5,
JKEYCODE_ENDCALL = 6,
JKEYCODE_VOLUME_UP = 24,
JKEYCODE_VOLUME_DOWN = 25,
JKEYCODE_POWER = 26,
JKEYCODE_CAMERA = 27,
JKEYCODE_HEADSETHOOK = 79,
JKEYCODE_FOCUS = 80,
JKEYCODE_MENU = 82,
JKEYCODE_SEARCH = 84,
JKEYCODE_MUTE = 91,
JKEYCODE_MEDIA_PLAY_PAUSE = 85,
JKEYCODE_MEDIA_STOP = 86,
JKEYCODE_MEDIA_NEXT = 87,
JKEYCODE_MEDIA_PREVIOUS = 88,
JKEYCODE_MEDIA_REWIND = 89,
JKEYCODE_MEDIA_FAST_FORWARD = 90
};
// five-way navigation control
enum {
JKEYCODE_DPAD_UP = 19,
JKEYCODE_DPAD_DOWN = 20,
JKEYCODE_DPAD_LEFT = 21,
JKEYCODE_DPAD_RIGHT = 22,
JKEYCODE_DPAD_CENTER = 23
};
// meta modifier
enum {
JMETA_SHIFT = 0x01,
JMETA_ALT = 0x02,
JMETA_SYM = 0x04,
JMETA_CTRL = 0x1000
};
// map android key codes to our kbd codes
static const Common::KeyCode jkeymap[] = {
Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN
Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT
Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_HOME
Common::KEYCODE_INVALID, // KEYCODE_BACK
Common::KEYCODE_INVALID, // KEYCODE_CALL
Common::KEYCODE_INVALID, // KEYCODE_ENDCALL
Common::KEYCODE_0, // KEYCODE_0
Common::KEYCODE_1, // KEYCODE_1
Common::KEYCODE_2, // KEYCODE_2
Common::KEYCODE_3, // KEYCODE_3
Common::KEYCODE_4, // KEYCODE_4
Common::KEYCODE_5, // KEYCODE_5
Common::KEYCODE_6, // KEYCODE_6
Common::KEYCODE_7, // KEYCODE_7
Common::KEYCODE_8, // KEYCODE_8
Common::KEYCODE_9, // KEYCODE_9
Common::KEYCODE_ASTERISK, // KEYCODE_STAR
Common::KEYCODE_HASH, // KEYCODE_POUND
Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP
Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN
Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN
Common::KEYCODE_INVALID, // KEYCODE_POWER
Common::KEYCODE_INVALID, // KEYCODE_CAMERA
Common::KEYCODE_INVALID, // KEYCODE_CLEAR
Common::KEYCODE_a, // KEYCODE_A
Common::KEYCODE_b, // KEYCODE_B
Common::KEYCODE_c, // KEYCODE_C
Common::KEYCODE_d, // KEYCODE_D
Common::KEYCODE_e, // KEYCODE_E
Common::KEYCODE_f, // KEYCODE_F
Common::KEYCODE_g, // KEYCODE_G
Common::KEYCODE_h, // KEYCODE_H
Common::KEYCODE_i, // KEYCODE_I
Common::KEYCODE_j, // KEYCODE_J
Common::KEYCODE_k, // KEYCODE_K
Common::KEYCODE_l, // KEYCODE_L
Common::KEYCODE_m, // KEYCODE_M
Common::KEYCODE_n, // KEYCODE_N
Common::KEYCODE_o, // KEYCODE_O
Common::KEYCODE_p, // KEYCODE_P
Common::KEYCODE_q, // KEYCODE_Q
Common::KEYCODE_r, // KEYCODE_R
Common::KEYCODE_s, // KEYCODE_S
Common::KEYCODE_t, // KEYCODE_T
Common::KEYCODE_u, // KEYCODE_U
Common::KEYCODE_v, // KEYCODE_V
Common::KEYCODE_w, // KEYCODE_W
Common::KEYCODE_x, // KEYCODE_X
Common::KEYCODE_y, // KEYCODE_Y
Common::KEYCODE_z, // KEYCODE_Z
Common::KEYCODE_COMMA, // KEYCODE_COMMA
Common::KEYCODE_PERIOD, // KEYCODE_PERIOD
Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT
Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT
Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT
Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT
Common::KEYCODE_TAB, // KEYCODE_TAB
Common::KEYCODE_SPACE, // KEYCODE_SPACE
Common::KEYCODE_LCTRL, // KEYCODE_SYM
Common::KEYCODE_INVALID, // KEYCODE_EXPLORER
Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE
Common::KEYCODE_RETURN, // KEYCODE_ENTER
Common::KEYCODE_BACKSPACE, // KEYCODE_DEL
Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE
Common::KEYCODE_MINUS, // KEYCODE_MINUS
Common::KEYCODE_EQUALS, // KEYCODE_EQUALS
Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET
Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET
Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH
Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON
Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE
Common::KEYCODE_SLASH, // KEYCODE_SLASH
Common::KEYCODE_AT, // KEYCODE_AT
Common::KEYCODE_INVALID, // KEYCODE_NUM
Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK
Common::KEYCODE_INVALID, // KEYCODE_FOCUS
Common::KEYCODE_PLUS, // KEYCODE_PLUS
Common::KEYCODE_INVALID, // KEYCODE_MENU
Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION
Common::KEYCODE_INVALID, // KEYCODE_SEARCH
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD
Common::KEYCODE_INVALID, // KEYCODE_MUTE
Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP
Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN
};
#endif

View File

@ -41,6 +41,7 @@
#include "common/endian.h"
#include "graphics/conversion.h"
#include "graphics/opengles2/shader.h"
#include "backends/platform/android/android.h"
#include "backends/platform/android/jni.h"
@ -52,7 +53,7 @@ static inline GLfixed xdiv(int numerator, int denominator) {
// ResidualVM specific method
void OSystem_Android::launcherInitSize(uint w, uint h) {
//setupScreen(w, h, true, false);
setupScreen(w, h, true, true, false);
}
// ResidualVM specific method
@ -191,7 +192,7 @@ void OSystem_Android::initSurface() {
JNI::initSurface();
// Initialize OpenGLES context.
GLESTexture::initGLExtensions();
GLESTexture::initGL();
if (_game_texture)
_game_texture->reinit();
@ -233,44 +234,14 @@ void OSystem_Android::initViewport() {
assert(JNI::haveSurface());
if (_opengl) {
GLCALL(glEnable(GL_DITHER));
GLCALL(glShadeModel(GL_SMOOTH));
GLCALL(glDisableClientState(GL_VERTEX_ARRAY));
GLCALL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
GLCALL(glDisable(GL_TEXTURE_2D));
GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST));
} else {
// Turn off anything that looks like 3D ;)
GLCALL(glDisable(GL_DITHER));
GLCALL(glShadeModel(GL_FLAT));
GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GLCALL(glEnable(GL_TEXTURE_2D));
GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
}
GLCALL(glDisable(GL_CULL_FACE));
GLCALL(glDisable(GL_DEPTH_TEST));
GLCALL(glDisable(GL_LIGHTING));
GLCALL(glDisable(GL_FOG));
GLCALL(glEnable(GL_BLEND));
GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
GLCALL(glMatrixMode(GL_PROJECTION));
GLCALL(glLoadIdentity());
GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1));
GLCALL(glMatrixMode(GL_MODELVIEW));
GLCALL(glLoadIdentity());
LOGD("viewport size: %dx%d", _egl_surface_width, _egl_surface_height);
clearFocusRectangle();
}
@ -287,10 +258,10 @@ void OSystem_Android::initOverlay() {
// enforces the 'lowres' layout, which will be scaled back up by factor 2x,
// but this looks way better than the 'normal' layout scaled by some
// calculated factors
while (overlay_height > 480) {
overlay_width /= 2;
overlay_height /= 2;
}
// while (overlay_height > 480) {
// overlay_width /= 2;
// overlay_height /= 2;
// }
LOGI("overlay size is %ux%u", overlay_width, overlay_height);
@ -333,7 +304,7 @@ void OSystem_Android::clearScreen(FixupType type, byte count) {
for (byte i = 0; i < count; ++i) {
// clear screen
GLCALL(glClearColorx(0, 0, 0, 1 << 16));
GLCALL(glClearColor(0, 0, 0, 1 << 16));
if (_opengl) {
GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
} else {
@ -460,15 +431,20 @@ void OSystem_Android::copyRectToScreen(const void *buf, int pitch,
// ResidualVM specific method
Graphics::PixelBuffer OSystem_Android::setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d) {
Graphics::PixelBuffer OSystem_Android::setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d, bool isGame) {
_opengl = accel3d;
initViewport();
_touchControls.init(this, _egl_surface_width, _egl_surface_height);
if (_opengl) {
// resize game texture
initSize(screenW, screenH, 0);
if (isGame)
_game_texture->setGameTexture();
// format is not used by the gfx_opengl driver, use fake format
_game_pbuf.set(Graphics::PixelFormat(), 0);
} else {
Graphics::PixelFormat format = GLES565Texture::pixelFormat();
initSize(screenW, screenH, &format);
@ -488,7 +464,6 @@ void OSystem_Android::updateScreen() {
if (!JNI::haveSurface())
return;
if (!_opengl) {
if (_game_pbuf) {
int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
_game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
@ -509,8 +484,8 @@ void OSystem_Android::updateScreen() {
if ((_show_overlay || _htc_fail) && !_fullscreen)
clearScreen(kClear);
GLCALL(glPushMatrix());
// TODO: Do we have engines that use this?
#if 0
if (_shake_offset != 0 ||
(!_focus_rect.isEmpty() &&
!Common::Rect(_game_texture->width(),
@ -522,14 +497,18 @@ void OSystem_Android::updateScreen() {
// Move everything up by _shake_offset (game) pixels
GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
}
#endif
// TODO this doesnt work on those sucky drivers, do it differently
// if (_show_overlay)
// GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f));
if (_focus_rect.isEmpty()) {
if (true || _focus_rect.isEmpty()) {
_game_texture->drawTextureRect();
drawVirtControls();
} else {
// TODO what is this and do we have engines using it?
#if 0
GLCALL(glPushMatrix());
GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
@ -544,6 +523,7 @@ void OSystem_Android::updateScreen() {
_game_texture->drawTextureRect();
GLCALL(glPopMatrix());
#endif
}
int cs = _mouse_targetscale;
@ -559,17 +539,13 @@ void OSystem_Android::updateScreen() {
}
if (_show_mouse && !_mouse_texture->isEmpty()) {
GLCALL(glPushMatrix());
const Common::Point &mouse = getEventManager()->getMousePos();
// Scale up ResidualVM -> OpenGL (pixel) coordinates
if (_show_overlay) {
GLCALL(glScalex(xdiv(_egl_surface_width,
_overlay_texture->width()),
xdiv(_egl_surface_height,
_overlay_texture->height()),
1 << 16));
_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
}
// TODO: Port the non-overlay code as well?
#if 0
if (_show_overlay) {
} else {
const Common::Rect &r = _game_texture->getDrawRect();
@ -585,23 +561,20 @@ void OSystem_Android::updateScreen() {
(-_mouse_hotspot.y * cs) << 16,
0));
// Note the extra half texel to position the mouse in
// the middle of the x,y square:
GLCALL(glTranslatex((mouse.x << 16) | 1 << 15,
(mouse.y << 16) | 1 << 15, 0));
GLCALL(glScalex(cs << 16, cs << 16, 1 << 16));
_mouse_texture->drawTextureOrigin();
GLCALL(glPopMatrix());
}
GLCALL(glPopMatrix());
#endif
}
if (!JNI::swapBuffers())
LOGW("swapBuffers failed: 0x%x", glGetError());
}
void OSystem_Android::drawVirtControls() {
if (_show_overlay)
return;
glEnable(GL_BLEND);
_touchControls.draw();
}
Graphics::Surface *OSystem_Android::lockScreen() {

View File

@ -6,7 +6,8 @@ MODULE_OBJS := \
asset-archive.o \
android.o \
gfx.o \
events.o
events.o \
touchcontrols.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))

View File

@ -151,7 +151,14 @@ public abstract class ResidualVM implements SurfaceHolder.Callback, Runnable {
_egl.eglInitialize(_egl_display, version);
int[] num_config = new int[1];
_egl.eglGetConfigs(_egl_display, null, 0, num_config);
int[] config_attrib_list = {
EGL10.EGL_RENDERABLE_TYPE, 4, // ES2
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_NONE
};
_egl.eglChooseConfig(_egl_display, config_attrib_list, null, 0, num_config);
final int numConfigs = num_config[0];
@ -159,14 +166,14 @@ public abstract class ResidualVM implements SurfaceHolder.Callback, Runnable {
throw new IllegalArgumentException("No EGL configs");
EGLConfig[] configs = new EGLConfig[numConfigs];
_egl.eglGetConfigs(_egl_display, configs, numConfigs, num_config);
_egl.eglChooseConfig(_egl_display, config_attrib_list, configs, numConfigs, num_config);
// Android's eglChooseConfig is busted in several versions and
// devices so we have to filter/rank the configs ourselves.
_egl_config = chooseEglConfig(configs);
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE };
_egl_context = _egl.eglCreateContext(_egl_display, _egl_config,
EGL10.EGL_NO_CONTEXT, null);
EGL10.EGL_NO_CONTEXT, attrib_list);
if (_egl_context == EGL10.EGL_NO_CONTEXT)
throw new Exception(String.format("Failed to create context: 0x%x",

View File

@ -8,6 +8,10 @@ import android.os.Bundle;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.MotionEvent;
@ -158,6 +162,21 @@ public class ResidualVMActivity extends Activity {
_residualvm_thread = new Thread(_residualvm, "ResidualVM");
_residualvm_thread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.game_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.show_menu:
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onStart() {

View File

@ -2,6 +2,7 @@ package org.residualvm.residualvm;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.content.Context;
import android.view.KeyEvent;
@ -30,11 +31,15 @@ public class ResidualVMEvents implements
public static final int JE_LONG = 10;
public static final int JE_FLING = 11;
public static final int JE_QUIT = 0x1000;
private final int REL_SWIPE_MIN_DISTANCE;
private final int REL_SWIPE_THRESHOLD_VELOCITY;
final protected Context _context;
final protected ResidualVM _residualvm;
final protected GestureDetector _gd;
final protected int _longPress;
final protected int _width;
public ResidualVMEvents(Context context, ResidualVM residualvm) {
_context = context;
@ -45,6 +50,11 @@ public class ResidualVMEvents implements
//_gd.setIsLongpressEnabled(false);
_longPress = ViewConfiguration.getLongPressTimeout();
DisplayMetrics dm = context.getResources().getDisplayMetrics();
REL_SWIPE_MIN_DISTANCE = (int)(120 * dm.densityDpi / 160.0f);
REL_SWIPE_THRESHOLD_VELOCITY = (int)(100 * dm.densityDpi / 160.0f);
_width = dm.widthPixels;
}
final public void sendQuitEvent() {
@ -74,6 +84,7 @@ public class ResidualVMEvents implements
}
};
// OnKeyListener
final public boolean onKey(View v, int keyCode, KeyEvent e) {
final int action = e.getAction();
@ -162,26 +173,33 @@ public class ResidualVMEvents implements
}
final public boolean onTouchEvent(MotionEvent e) {
final int action = e.getAction();
_gd.onTouchEvent(e);
final int action = e.getActionMasked();
// constants from APIv5:
// (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT
final int pointer = (action & 0xff00) >> 8;
final int x0 = (int)e.getX();
final int y0 = (int)e.getY();
final int x1 = (e.getPointerCount() > 1 ? (int)e.getX(1) : -1);
final int y1 = (e.getPointerCount() > 1 ? (int)e.getY(1) : -1);
if (pointer > 0) {
_residualvm.pushEvent(JE_MULTI, pointer, action & 0xff, // ACTION_MASK
x0, y0, x1, y1);
// ACTION_MOVE always returns the first pointer as the "active" one.
if (action == MotionEvent.ACTION_MOVE) {
for (int idx = 0; idx < e.getPointerCount(); ++idx) {
final int pointer = e.getPointerId(idx);
final int x = (int)e.getX(idx);
final int y = (int)e.getY(idx);
_residualvm.pushEvent(JE_TOUCH, pointer, action, x, y, 0, 0);
}
} else {
_residualvm.pushEvent(JE_TOUCH, pointer, action & 0xff, // ACTION_MASK
x0, y0, x1, y1);
final int idx = e.getActionIndex();
final int pointer = e.getPointerId(idx);
final int x = (int)e.getX(idx);
final int y = (int)e.getY(idx);
_residualvm.pushEvent(JE_TOUCH, pointer, action, x, y, 0, 0);
}
return _gd.onTouchEvent(e);
return true;
}
// OnGestureListener
@ -192,9 +210,16 @@ public class ResidualVMEvents implements
final public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
_residualvm.pushEvent(JE_FLING, (int)e1.getX(), (int)e1.getY(),
(int)e2.getX(), (int)e2.getY(), 0, 0);
return true;
return false;
// if (e1.getX() < 0.4 * _width
// || Math.abs(e1.getX() - e2.getX()) < REL_SWIPE_MIN_DISTANCE
// || velocityX < REL_SWIPE_THRESHOLD_VELOCITY
// || Math.abs(e1.getY() - e2.getY()) < REL_SWIPE_MIN_DISTANCE
// || velocityY < REL_SWIPE_THRESHOLD_VELOCITY)
// return false;
//
// _residualvm.pushEvent(JE_FLING, (int)e1.getX(), (int)e1.getY(),
// (int)e2.getX(), (int)e2.getY(), 0, 0);
}
final public void onLongPress(MotionEvent e) {

View File

@ -271,7 +271,7 @@ public class Unpacker extends Activity {
unpack_libs.add(new Uri.Builder()
.scheme("plugin")
.authority(getPackageName())
.path("mylib/armeabi/libresidualvm.so")
.path("lib/armeabi/libresidualvm.so")
.toString());
extras.putStringArrayList(ResidualVMApplication.EXTRA_UNPACK_LIBS,
unpack_libs);

View File

@ -41,6 +41,7 @@
#include "base/main.h"
#include "graphics/surface.h"
#include "graphics/opengles2/shader.h"
#include "common/rect.h"
#include "common/array.h"
@ -49,12 +50,13 @@
#include "backends/platform/android/texture.h"
#include "backends/platform/android/android.h"
#include "backends/platform/android/jni.h"
// Supported GL extensions
static bool npot_supported = false;
#ifdef GL_OES_draw_texture
static bool draw_tex_supported = false;
#endif
Graphics::Shader * g_box_shader;
GLuint g_verticesVBO;
static inline GLfixed xdiv(int numerator, int denominator) {
assert(numerator < (1 << 16));
@ -73,7 +75,14 @@ static T nextHigher2(T k) {
return k + 1;
}
void GLESBaseTexture::initGLExtensions() {
const GLfloat vertices[] = {
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 1.0,
};
void GLESBaseTexture::initGL() {
const char *ext_string =
reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
@ -85,12 +94,13 @@ void GLESBaseTexture::initGLExtensions() {
if (token == "GL_ARB_texture_non_power_of_two")
npot_supported = true;
#ifdef GL_OES_draw_texture
if (token == "GL_OES_draw_texture")
draw_tex_supported = true;
#endif
}
const char* attributes[] = { "position", "texcoord", NULL };
g_box_shader = Graphics::Shader::fromStrings("control", Graphics::BuiltinShaders::controlVertex, Graphics::BuiltinShaders::controlFragment, attributes);
g_verticesVBO = Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
g_box_shader->enableVertexAttribute("position", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
g_box_shader->enableVertexAttribute("texcoord", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
}
GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
@ -106,7 +116,8 @@ GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
_all_dirty(false),
_dirty_rect(),
_pixelFormat(pixelFormat),
_palettePixelFormat()
_palettePixelFormat(),
_is_game_texture(false)
{
GLCALL(glGenTextures(1, &_texture_name));
}
@ -117,8 +128,6 @@ GLESBaseTexture::~GLESBaseTexture() {
void GLESBaseTexture::release() {
if (_texture_name) {
LOGD("Destroying texture %u", _texture_name);
GLCALL(glDeleteTextures(1, &_texture_name));
_texture_name = 0;
}
@ -177,48 +186,28 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
initSize();
}
void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
// LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
assert(g_box_shader);
g_box_shader->use();
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
const GLfloat offsetX = float(x) / float(JNI::egl_surface_width);
const GLfloat offsetY = float(y) / float(JNI::egl_surface_height);
const GLfloat sizeW = float(w) / float(JNI::egl_surface_width);
const GLfloat sizeH = float(h) / float(JNI::egl_surface_height);
Math::Vector4d clipV = Math::Vector4d(clip.left, clip.top, clip.right, clip.bottom);
clipV.x() /= _texture_width; clipV.y() /= _texture_height;
clipV.z() /= _texture_width; clipV.w() /= _texture_height;
// LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h), tex_width, tex_height);
#ifdef GL_OES_draw_texture
// Great extension, but only works under specific conditions.
// Still a work-in-progress - disabled for now.
if (false && draw_tex_supported && !hasPalette()) {
//GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h };
g_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
g_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
g_box_shader->setUniform("clip", clipV);
g_box_shader->setUniform("flipY", !_is_game_texture);
GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop));
// Android GLES bug?
GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff));
GLCALL(glDrawTexiOES(x, y, 0, w, h));
} else
#endif
{
const GLfixed tex_width = xdiv(_surface.w, _texture_width);
const GLfixed tex_height = xdiv(_surface.h, _texture_height);
const GLfixed texcoords[] = {
0, 0,
tex_width, 0,
0, tex_height,
tex_width, tex_height,
};
GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords));
const GLshort vertices[] = {
x, y,
x + w, y,
x, y + h,
x + w, y + h,
};
GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices));
assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords));
GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2));
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
clearDirty();
}
@ -293,7 +282,7 @@ void GLESTexture::fillBuffer(uint32 color) {
setDirty();
}
void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
if (_all_dirty) {
_dirty_rect.top = 0;
_dirty_rect.left = 0;
@ -335,7 +324,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
dwidth, dheight, _glFormat, _glType, _tex));
}
GLESBaseTexture::drawTexture(x, y, w, h);
GLESBaseTexture::drawTexture(x, y, w, h, clip);
}
GLES4444Texture::GLES4444Texture() :
@ -345,6 +334,13 @@ GLES4444Texture::GLES4444Texture() :
GLES4444Texture::~GLES4444Texture() {
}
GLES8888Texture::GLES8888Texture() :
GLESTexture(GL_RGBA, GL_UNSIGNED_BYTE, pixelFormat()) {
}
GLES8888Texture::~GLES8888Texture() {
}
GLES5551Texture::GLES5551Texture() :
GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) {
}
@ -431,8 +427,7 @@ void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
} while (--h);
}
void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
GLshort h) {
void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
if (_all_dirty) {
_dirty_rect.top = 0;
_dirty_rect.left = 0;
@ -464,7 +459,7 @@ void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
dwidth, dheight, _glFormat, _glType, _buf));
}
GLESBaseTexture::drawTexture(x, y, w, h);
GLESBaseTexture::drawTexture(x, y, w, h, clip);
}
const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {

View File

@ -36,7 +36,7 @@
class GLESBaseTexture {
public:
static void initGLExtensions();
static void initGL();
protected:
GLESBaseTexture(GLenum glFormat, GLenum glType,
@ -57,7 +57,11 @@ public:
const void *buf, int pitch_buf) = 0;
virtual void fillBuffer(uint32 color) = 0;
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
}
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
inline void setDrawRect(const Common::Rect &rect) {
_draw_rect = rect;
@ -92,6 +96,14 @@ public:
return _surface.h;
}
inline GLuint texWidth() const {
return _texture_width;
}
inline GLuint texHeight() const {
return _texture_height;
}
inline uint16 pitch() const {
return _surface.pitch;
}
@ -131,6 +143,14 @@ public:
return _palettePixelFormat;
}
GLuint getTextureName() const {
return _texture_name;
}
void setGameTexture() {
_is_game_texture = true;
}
protected:
inline void setDirty() {
_all_dirty = true;
@ -169,6 +189,8 @@ protected:
Graphics::PixelFormat _pixelFormat;
Graphics::PixelFormat _palettePixelFormat;
bool _is_game_texture;
};
class GLESTexture : public GLESBaseTexture {
@ -185,13 +207,26 @@ public:
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
}
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
protected:
byte *_pixels;
byte *_buf;
};
class GLES8888Texture : public GLESTexture {
public:
GLES8888Texture();
virtual ~GLES8888Texture();
static Graphics::PixelFormat pixelFormat() {
return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
}
};
// RGBA4444 texture
class GLES4444Texture : public GLESTexture {
public:
@ -238,7 +273,10 @@ public:
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
}
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
virtual const byte *palette_const() const {
return (byte *)_palette;

View File

@ -0,0 +1,264 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#if defined(__ANDROID__)
#include "common/fs.h"
#include "common/stream.h"
#include "common/archive.h"
#include "graphics/decoders/tga.h"
#include "backends/platform/android/events.h"
#include "backends/platform/android/texture.h"
#include "backends/platform/android/touchcontrols.h"
static Common::Rect clipFor(const Common::KeyCode &cs) {
switch (cs) {
case Common::KEYCODE_UP:
case Common::KEYCODE_PAGEUP:
return Common::Rect(0, 0, 128, 128);
case Common::KEYCODE_RIGHT:
return Common::Rect(128, 0, 256, 128);
case Common::KEYCODE_DOWN:
case Common::KEYCODE_PAGEDOWN:
return Common::Rect(256, 0, 384, 128);
case Common::KEYCODE_LEFT:
return Common::Rect(384, 0, 512, 128);
case Common::KEYCODE_i:
return Common::Rect(0, 128, 128, 256);
case Common::KEYCODE_p:
return Common::Rect(128, 128, 256, 256);
case Common::KEYCODE_u:
return Common::Rect(256, 128, 384, 256);
case Common::KEYCODE_e:
case Common::KEYCODE_l:
return Common::Rect(384, 128, 512, 256);
default: // unreachable
return Common::Rect(0, 0, 1, 1);
}
}
TouchControls::TouchControls() :
_arrows_texture(NULL),
_joystickPressing(Common::KEYCODE_INVALID),
_centerPressing(Common::KEYCODE_INVALID),
_rightPressing(Common::KEYCODE_INVALID),
_key_receiver(NULL),
_screen_width(0),
_screen_height(0) {
for (int p = 0; p < kNumPointers; ++p) {
Pointer &pp = _pointers[p];
pp.currentX = pp.currentY = pp.startX = pp.startY = 0;
pp.active = false;
pp.function = kTouchAreaNone;
}
for (int i = 0; i < 4; ++i)
_activePointers[i] = -1;
}
TouchControls::~TouchControls() {
if (_arrows_texture) {
delete _arrows_texture;
_arrows_texture = 0;
}
}
uint16 TouchControls::getTouchArea(int x, int y) {
float xPercent = float(x) / _screen_width;
if (xPercent < 0.3)
return kTouchAreaJoystick;
else if (xPercent < 0.8)
return kTouchAreaCenter;
else
return kTouchAreaRight;
}
static Common::KeyCode determineKey(int dX, int dY, Common::KeyCode def = Common::KEYCODE_INVALID) {
if (dX * dX + dY * dY < 50 * 50)
return def;
if (dY > abs(dX))
return Common::KEYCODE_DOWN;
if (dX > abs(dY))
return Common::KEYCODE_RIGHT;
if (-dY > abs(dX))
return Common::KEYCODE_UP;
if (-dX > abs(dY))
return Common::KEYCODE_LEFT;
return Common::KEYCODE_INVALID;
}
static GLES8888Texture *loadBuiltinTexture(const char *filename) {
Common::ArchiveMemberPtr member = SearchMan.getMember(filename);
Common::SeekableReadStream *str = member->createReadStream();
Graphics::TGADecoder dec;
dec.loadStream(*str);
void *pixels = dec.getSurface()->pixels;
GLES8888Texture *ret = new GLES8888Texture();
uint16 w = dec.getSurface()->w;
uint16 h = dec.getSurface()->h;
uint16 pitch = dec.getSurface()->pitch;
ret->allocBuffer(w, h);
ret->updateBuffer(0, 0, w, h, pixels, pitch);
delete str;
return ret;
}
void TouchControls::init(KeyReceiver *kr, int width, int height) {
_arrows_texture = loadBuiltinTexture("arrows.tga");
_screen_width = width;
_screen_height = height;
_key_receiver = kr;
}
const uint _numRightKeycodes = 4;
const Common::KeyCode _rightKeycodes[] = { Common::KEYCODE_i, Common::KEYCODE_p, Common::KEYCODE_u, Common::KEYCODE_e };
void TouchControls::draw() {
if (_joystickPressing != Common::KEYCODE_INVALID) {
Common::Rect clip = clipFor(_joystickPressing);
_arrows_texture->drawTexture(2 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
}
if (_centerPressing != Common::KEYCODE_INVALID) {
Common::Rect clip = clipFor(_centerPressing);
_arrows_texture->drawTexture(_screen_width / 2, _screen_height / 2, 64, 64, clip);
}
if (_rightPressing != Common::KEYCODE_INVALID) {
Common::Rect clip = clipFor(_rightPressing);
_arrows_texture->drawTexture( 8 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
}
}
void TouchControls::update(int ptr, int action, int x, int y) {
if (ptr > kNumPointers)
return;
TouchArea touchArea = (TouchArea) getTouchArea(x, y);
switch (action) {
case JACTION_POINTER_DOWN:
case JACTION_DOWN:
if (touchArea > kTouchAreaNone && -1 == pointerFor(touchArea)) {
pointerFor(touchArea) = ptr;
_pointers[ptr].active = true;
_pointers[ptr].function = touchArea;
_pointers[ptr].startX = _pointers[ptr].currentX = x;
_pointers[ptr].startY = _pointers[ptr].currentY = y;
// fall through to move case to initialize _{joy,center,right}Pressing
} else {
return;
}
case JACTION_MOVE: {
_pointers[ptr].currentX = x;
_pointers[ptr].currentY = y;
int dX = x - _pointers[ptr].startX;
int dY = y - _pointers[ptr].startY;
switch (_pointers[ptr].function) {
case kTouchAreaJoystick: {
Common::KeyCode newPressing = determineKey(dX, dY);
if (newPressing != _joystickPressing) {
_key_receiver->keyPress(_joystickPressing, KeyReceiver::UP);
_key_receiver->keyPress(newPressing, KeyReceiver::DOWN);
_joystickPressing = newPressing;
}
return;
}
case kTouchAreaCenter:
_centerPressing = determineKey(dX, dY, Common::KEYCODE_RETURN);
return;
case kTouchAreaRight:
_rightPressing = determineKey(dX, dY, Common::KEYCODE_i);
switch (_rightPressing) {
case Common::KEYCODE_LEFT:
case Common::KEYCODE_RIGHT:
_rightPressing = _rightKeycodes[abs(dX / 100) % _numRightKeycodes];
break;
case Common::KEYCODE_UP:
_rightPressing = Common::KEYCODE_PAGEUP;
break;
case Common::KEYCODE_DOWN:
_rightPressing = Common::KEYCODE_PAGEDOWN;
break;
default:
break;
}
default:
return;
}
return;
}
case JACTION_UP:
case JACTION_POINTER_UP: {
switch (_pointers[ptr].function) {
case kTouchAreaJoystick:
pointerFor(kTouchAreaJoystick) = -1;
if (_joystickPressing != Common::KEYCODE_INVALID) {
_key_receiver->keyPress(_joystickPressing, KeyReceiver::UP);
_joystickPressing = Common::KEYCODE_INVALID;
}
break;
case kTouchAreaCenter:
pointerFor(kTouchAreaCenter) = -1;
_key_receiver->keyPress(_centerPressing);
_centerPressing = Common::KEYCODE_INVALID;
break;
case kTouchAreaRight:
pointerFor(kTouchAreaRight) = -1;
_key_receiver->keyPress(_rightPressing);
_rightPressing = Common::KEYCODE_INVALID;
break;
case kTouchAreaNone:
default:
break;
}
_pointers[ptr].active = false;
_pointers[ptr].function = kTouchAreaNone;
return;
}
}
}
int &TouchControls::pointerFor(TouchArea ta) {
return _activePointers[ta - kTouchAreaNone];
}
#endif

View File

@ -0,0 +1,73 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ANDROID_TOUCHCONTROLS_H_
#define ANDROID_TOUCHCONTROLS_H_
#if defined(__ANDROID__)
#include "common/events.h"
#include "backends/platform/android/events.h"
#include "backends/platform/android/texture.h"
class TouchControls {
public:
TouchControls();
~TouchControls();
void init(KeyReceiver *kr, int width, int height);
void draw();
void update(int ptr, int action, int x, int y);
private:
int _screen_width, _screen_height;
KeyReceiver *_key_receiver;
enum TouchArea{
kTouchAreaJoystick = 0xffff,
kTouchAreaCenter = 0xfffe,
kTouchAreaRight = 0xfffd,
kTouchAreaNone = 0xfffc,
};
uint16 getTouchArea(int x, int y);
struct Pointer {
uint16 startX, startY;
uint16 currentX, currentY;
TouchArea function;
bool active;
};
enum { kNumPointers = 5 };
Pointer _pointers[kNumPointers];
int _activePointers[4];
Common::KeyCode _joystickPressing, _centerPressing, _rightPressing;
int &pointerFor(TouchArea ta);
GLESTexture *_arrows_texture;
};
#endif
#endif

View File

@ -312,6 +312,7 @@ public:
//ResidualVM specific
kFeatureOpenGL,
kFeatureVirtControls,
/**
* The presence of this feature indicates whether the displayLogFile()

36
configure vendored
View File

@ -104,7 +104,7 @@ _srcdir=`dirname $0`
#
#ResidualVM defaults: mpeg2=auto, faad=no, opengles=no, vorbis=no, tremor=no
# mt32emu=no, translation=no, flac=no, seq_midi=no, snd_io=no, timidity=no, png=no
# theoradec=no, fluidsynth=no
# theoradec=no, fluidsynth=no, opengles2=no
#
# Default lib behaviour yes/no/auto
_vorbis=no
@ -125,6 +125,7 @@ _faad=no
_fluidsynth=no
_opengl=auto
_opengles=no
_opengles2=no
_readline=auto
_freetype2=auto
_taskbar=yes
@ -178,6 +179,8 @@ _nasmpath="$PATH"
NASMFLAGS=""
NASM=""
_tainted_build=no
# residualvm specific
_android_sysroot_path=""
# The following variables are automatically detected, and should not
# be modified otherwise. Consider them read-only.
_posix=no
@ -1478,6 +1481,15 @@ android)
echo "Please set ANDROID_NDK in your environment. export ANDROID_NDK=<path to Android NDK>"
exit 1
fi
# residualvm specific
if test ! -d android-toolchain; then
echo "Installing Android toolchain to build directory..."
"$ANDROID_NDK/build/tools/make-standalone-toolchain.sh" --platform=android-8 --install-dir=android-toolchain
else
echo "Android toolchain already installed."
fi
PATH="android-toolchain/bin:$PATH"
_android_sysroot_path="android-toolchain/bin:"
;;
bada)
if test -z "$BADA_SDK"; then
@ -1990,7 +2002,7 @@ case $_host_os in
;;
esac
# ResidualVM use newer NDK
CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-5/arch-arm"
CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-8/arch-arm"
CXXFLAGS="$CXXFLAGS -fpic"
CXXFLAGS="$CXXFLAGS -ffunction-sections"
CXXFLAGS="$CXXFLAGS -funwind-tables"
@ -2012,7 +2024,7 @@ case $_host_os in
# supress 'mangling of 'va_list' has changed in GCC 4.4'
CXXFLAGS="$CXXFLAGS -Wno-psabi"
# ResidualVM use newer NDK
LDFLAGS="$LDFLAGS --sysroot=$ANDROID_NDK/platforms/android-5/arch-arm"
LDFLAGS="$LDFLAGS --sysroot=$ANDROID_NDK/platforms/android-8/arch-arm"
LDFLAGS="$LDFLAGS -mthumb-interwork"
add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK"
_seq_midi=no
@ -2656,6 +2668,8 @@ case $_backend in
CXXFLAGS="$CXXFLAGS -Wa,--noexecstack"
LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"
INCLUDES="$INCLUDES -I$ANDROID_NDK/sources/cxx-stl/system/include"
DEFINES="$DEFINES -DANDROID_BACKEND"
add_line_to_config_mk "ANDROID_BACKEND = 1"
;;
bada)
# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
@ -3701,6 +3715,8 @@ EOF
break
fi
done
elif test "$_opengles2" = "yes" ; then
OPENGL_LIBS="$OPENGL_LIBS -lGLESv2"
else
case $_host_os in
darwin*)
@ -3732,16 +3748,24 @@ case $_host_os in
_opengl=yes
_opengles=yes
;;
android)
_opengles2=yes
LDFLAGS="$LDFLAGS -Landroid-toolchain/sysroot/usr/lib"
LDFLAGS="$LDFLAGS -lGLESv2"
;;
esac
if test "$_opengles" = "yes" ; then
echo "yes (OpenGL ES)"
elif test "$_opengles2" = "yes" ; then
echo "yes (OpenGL ES2)"
else
echo "$_opengl"
fi
define_in_config_if_yes "$_opengl" "USE_OPENGL"
define_in_config_if_yes "$_opengles" "USE_GLES"
define_in_config_if_yes "$_opengles2" "USE_GLES2"
#
@ -4016,7 +4040,10 @@ case $_backend in
# -lgcc is carefully placed here - we want to catch
# all toolchain symbols in *our* libraries rather
# than pick up anything unhygenic from the Android libs.
LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -llog -lGLESv1_CM"
LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -llog"
if test "$_opengles2" != "yes" ; then
LIBS="$LIBS -lGLESv1_CM"
fi
;;
n64)
# Move some libs down here, otherwise some symbols requires by libvorbis aren't found
@ -4212,6 +4239,7 @@ STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path
AOS4PATH=$_aos4path
STATICLIBPATH=$_staticlibpath
PATH := ${_android_sysroot_path}\$(PATH)
BACKEND := $_backend
MODULES += $MODULES

View File

@ -3,14 +3,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.residualvm.residualvm"
android:versionCode="@ANDROID_VERSIONCODE@"
android:versionCode="1000"
android:versionName="0.2.0git"
android:installLocation="preferExternal"
android:sharedUserId="org.residualvm.residualvm">
<!-- This version works on Android 1.5 (SDK 3) and newer, but we
want Android 2.2 (SDK 8) defaults and features. -->
<uses-sdk android:minSdkVersion="5"
<uses-sdk android:minSdkVersion="8"
android:targetSdkVersion="8"/>
<application android:name=".ResidualVMApplication"
@ -47,6 +45,7 @@
android:protectionLevel="signature"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Always needs some sort of qwerty keyboard.
Can work with a D-pad / trackball -->
@ -59,4 +58,6 @@
<uses-configuration android:reqTouchScreen="stylus"
android:reqKeyboardType="qwerty"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
</manifest>

View File

@ -8,14 +8,13 @@
android:installLocation="preferExternal"
android:sharedUserId="org.residualvm.residualvm">
<!-- This version works on Android 1.5 (SDK 3) and newer, but we
want Android 2.2 (SDK 8) defaults and features. -->
<uses-sdk android:minSdkVersion="5"
<uses-sdk android:minSdkVersion="8"
android:targetSdkVersion="8"/>
<application android:name=".ResidualVMApplication"
android:label="@string/app_name"
android:description="@string/app_desc"
android:debuggable="true"
android:icon="@drawable/residualvm">
<activity android:name=".ResidualVMActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@ -47,6 +46,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- Always needs some sort of qwerty keyboard.
Can work with a D-pad / trackball -->
<uses-configuration android:reqFiveWayNav="true"

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

114
dists/android/build.xml Normal file
View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="ResidualVM" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<!--
<target name="-pre-build">
</target>
<target name="-pre-compile">
</target>
/* This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir} */
<target name="-post-compile">
</target>
-->
<!-- Override the built-in aapt task, don't compress assets. -->
<target name="-package-resources" depends="-crunch">
<!-- only package resources if *not* a library project -->
<do-only-if-not-library elseText="Library project: do not package resources..." >
<aapt executable="${aapt}"
command="package"
versioncode="${version.code}"
versionname="${version.name}"
debug="${build.is.packaging.debug}"
manifest="${out.manifest.abs.file}"
assets="${asset.absolute.dir}"
androidjar="${project.target.android.jar}"
apkfolder="${out.absolute.dir}"
nocrunch="${build.packaging.nocrunch}"
resourcefilename="${resource.package.file.name}"
resourcefilter="${aapt.resource.filter}"
libraryResFolderPathRefid="project.library.res.folder.path"
libraryPackagesRefid="project.library.packages"
libraryRFileRefid="project.library.bin.r.file.path"
previousBuildType="${build.last.target}"
buildType="${build.target}"
ignoreAssets="${aapt.ignore.assets}">
<res path="${out.res.absolute.dir}" />
<res path="${resource.absolute.dir}" />
<nocompress /> <!-- forces no compression on any files in assets or res/raw -->
</aapt>
</do-only-if-not-library>
</target>
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: custom -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
APP_ABI := armeabi
LOCAL_MODULE := residualvm
LOCAL_SRC_FILES := ../libresidualvm.so
include $(PREBUILT_SHARED_LIBRARY)

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,40 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-8

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/show_menu" android:titleCondensed="Menu" android:title="Show menu..."></item>
</menu>

View File

@ -21,6 +21,10 @@ MODULE_OBJS := \
decoders/jpeg.o \
decoders/tga.o \
pixelbuffer.o \
opengles2/shader.o \
opengles2/box_shaders.o \
opengles2/control_shaders.o \
opengles2/compat_shaders.o \
tinygl/api.o \
tinygl/arrays.o \
tinygl/clear.o \

View File

@ -0,0 +1,65 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/scummsys.h"
#ifdef USE_GLES2
namespace Graphics {
namespace BuiltinShaders {
const char *boxVertex =
"#version 100\n"
"attribute vec2 position;\n"
"attribute vec2 texcoord;\n"
"uniform vec2 offsetXY;\n"
"uniform vec2 sizeWH;\n"
"uniform vec2 texcrop;\n"
"uniform bool flipY;\n"
"varying vec2 Texcoord;\n"
"void main() {\n"
"Texcoord = texcoord * texcrop;\n"
"vec2 pos = offsetXY + position * sizeWH;\n"
"pos.x = pos.x * 2.0 - 1.0;\n"
"pos.y = pos.y * 2.0 - 1.0;\n"
"if (flipY)\n"
"pos.y *= -1.0;\n"
"gl_Position = vec4(pos, 0.0, 1.0);\n"
"}\n";
const char *boxFragment =
"#version 100\n"
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float;\n"
"#else\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 Texcoord;\n"
"uniform sampler2D tex;\n"
"void main() {\n"
"gl_FragColor = texture2D(tex, Texcoord);\n"
"}\n";
}
}
#endif

View File

@ -0,0 +1,57 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/scummsys.h"
#ifdef USE_GLES2
namespace Graphics {
namespace BuiltinShaders {
const char *compatVertex =
"#ifdef GL_ES\n"
"mediump float round(in mediump float x) {\n"
" return sign(x) * floor(abs(x) + .5);\n"
"}\n"
"#define in attribute\n"
"#define out varying\n"
"#endif\n";
const char *compatFragment =
"#ifdef GL_ES\n"
"#define in varying\n"
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float;\n"
"#else\n"
"precision mediump float;\n"
"#endif\n"
"#define OUTPUT\n"
"#define outColor gl_FragColor\n"
"#define texture texture2D\n"
"#else\n"
"#define OUTPUT out vec4 outColor;\n"
"#endif\n";
}
}
#endif

View File

@ -0,0 +1,65 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/scummsys.h"
#ifdef USE_GLES2
namespace Graphics {
namespace BuiltinShaders {
const char *controlVertex =
"#version 100\n"
"attribute vec2 position;\n"
"attribute vec2 texcoord;\n"
"uniform vec2 offsetXY;\n"
"uniform vec2 sizeWH;\n"
"uniform vec4 clip;\n"
"uniform bool flipY;\n"
"varying vec2 Texcoord;\n"
"void main() {\n"
"Texcoord = clip.xy + texcoord * (clip.zw - clip.xy);\n"
"vec2 pos = offsetXY + position * sizeWH;\n"
"pos.x = pos.x * 2.0 - 1.0;\n"
"pos.y = pos.y * 2.0 - 1.0;\n"
"if (flipY)\n"
"pos.y *= -1.0;\n"
"gl_Position = vec4(pos, 0.0, 1.0);\n"
"}\n";
const char *controlFragment =
"#version 100\n"
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float;\n"
"#else\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 Texcoord;\n"
"uniform sampler2D tex;\n"
"void main() {\n"
"gl_FragColor = texture2D(tex, Texcoord);\n"
"}\n";
}
}
#endif

View File

@ -0,0 +1,201 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/scummsys.h"
#ifdef USE_GLES2
#include "graphics/opengles2/shader.h"
namespace Graphics {
static const GLchar *readFile(const Common::String &filename) {
Common::File file;
file.open(Common::String("shaders/") + filename);
if (!file.isOpen())
error("Could not open shader %s!", filename.c_str());
const int32 size = file.size();
GLchar *shaderSource = new GLchar[size + 1];
file.read(shaderSource, size);
file.close();
shaderSource[size] = '\0';
return shaderSource;
}
static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char buffer[512];
glGetShaderInfoLog(shader, 512, NULL, buffer);
error("Could not compile shader %s: %s", name.c_str(), buffer);
}
return shader;
}
static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
const GLchar *compatSource =
shaderType == GL_VERTEX_SHADER ? Graphics::BuiltinShaders::compatVertex : Graphics::BuiltinShaders::compatFragment;
const GLchar *shaderSources[] = {
"#version 100\n",
compatSource,
shaderSource
};
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 3, shaderSources, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char buffer[512];
glGetShaderInfoLog(shader, 512, NULL, buffer);
error("Could not compile shader %s: %s", name.c_str(), buffer);
}
return shader;
}
static GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType) {
const Common::String filename = Common::String(base) + "." + extension;
const GLchar *shaderSource = readFile(filename);
GLuint shader = createCompatShader(shaderSource, shaderType, filename);
delete[] shaderSource;
return shader;
}
Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char **attributes)
: _name(name) {
assert(attributes);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
for (int idx = 0; attributes[idx]; ++idx) {
glBindAttribLocation(shaderProgram, idx, attributes[idx]);
_attributes.push_back(VertexAttrib(idx, attributes[idx]));
}
glLinkProgram(shaderProgram);
_shaderNo = shaderProgram;
_uniforms = new Common::HashMap<Common::String, GLint>();
}
Shader *Shader::fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char **attributes) {
GLuint vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
GLuint fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
return new Shader(name, vertexShader, fragmentShader, attributes);
}
Shader *Shader::fromFiles(const char *vertex, const char *fragment, const char **attributes) {
GLuint vertexShader = loadShaderFromFile(vertex, "vertex", GL_VERTEX_SHADER);
GLuint fragmentShader = loadShaderFromFile(fragment, "fragment", GL_FRAGMENT_SHADER);
Common::String name = Common::String::format("%s/%s", vertex, fragment);
return new Shader(name, vertexShader, fragmentShader, attributes);
}
void Shader::use() {
static Shader *previousShader = NULL;
if (this == previousShader)
return;
previousShader = this;
glUseProgram(_shaderNo);
for (uint32 i = 0; i < _attributes.size(); ++i) {
Graphics::VertexAttrib &attrib = _attributes[i];
if (attrib._enabled) {
glEnableVertexAttribArray(i);
glBindBuffer(GL_ARRAY_BUFFER, attrib._vbo);
glVertexAttribPointer(i, attrib._size, attrib._type, attrib._normalized, attrib._stride, attrib._offset);
} else {
glDisableVertexAttribArray(i);
switch (attrib._size) {
case 2:
glVertexAttrib2fv(i, attrib._const);
break;
case 3:
glVertexAttrib3fv(i, attrib._const);
break;
case 4:
glVertexAttrib4fv(i, attrib._const);
break;
}
}
}
}
GLuint Shader::createBuffer(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(target, vbo);
glBufferData(target, size, data, usage);
return vbo;
}
VertexAttrib &Shader::getAttributeAt(uint32 idx) {
assert(idx < _attributes.size());
return _attributes[idx];
}
VertexAttrib &Shader::getAttribute(const char *attrib) {
for (uint32 i = 0; i < _attributes.size(); ++i)
if (_attributes[i]._name.equals(attrib))
return _attributes[i];
error("Could not find attribute %s in shader %s", attrib, _name.c_str());
return _attributes[0];
}
void Shader::enableVertexAttribute(const char *attrib, GLuint vbo, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uint32 offset) {
VertexAttrib &va = getAttribute(attrib);
va._enabled = true;
va._vbo = vbo;
va._size = size;
va._type = type;
va._normalized = normalized;
va._stride = stride;
va._offset = (const GLvoid *) offset;
}
void Shader::disableVertexAttribute(const char *attrib, int size, const float *data) {
VertexAttrib &va = getAttribute(attrib);
va._enabled = false;
va._size = size;
for (int i = 0; i < size; ++i)
va._const[i] = data[i];
}
}
#endif

148
graphics/opengles2/shader.h Normal file
View File

@ -0,0 +1,148 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/file.h"
#include "common/array.h"
#include "math/matrix3.h"
#include "math/matrix4.h"
#include "math/vector2d.h"
#include "math/vector3d.h"
#include "math/vector4d.h"
#include "graphics/opengles2/system_headers.h"
namespace Graphics {
namespace BuiltinShaders {
extern const char *boxVertex, *boxFragment;
extern const char *compatVertex, *compatFragment;
extern const char *controlVertex, *controlFragment;
}
struct VertexAttrib {
VertexAttrib(uint32 idx, const char *name) : _enabled(false), _idx(idx), _name(name), _vbo(0), _size(0), _type(GL_FLOAT), _normalized(false), _stride(0), _offset(NULL) {}
bool _enabled;
uint32 _idx;
Common::String _name;
GLuint _vbo;
GLint _size;
GLenum _type;
bool _normalized;
GLsizei _stride;
const GLvoid *_offset;
float _const[4];
};
class Shader {
typedef Common::HashMap<Common::String, GLint> UniformsMap;
public:
Shader* clone() {
return new Shader(*this);
}
void use();
void setUniform(const char *uniform, const Math::Matrix4 &m) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniformMatrix4fv(pos, 1, GL_FALSE, m.getData());
}
void setUniform(const char* uniform, const Math::Matrix3 &m) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniformMatrix3fv(pos, 1, GL_FALSE, m.getData());
}
void setUniform(const char *uniform, const Math::Vector4d &v) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniform4fv(pos, 1, v.getData());
}
void setUniform(const char *uniform, const Math::Vector3d &v) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniform3fv(pos, 1, v.getData());
}
void setUniform(const char *uniform, const Math::Vector2d &v) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniform2fv(pos, 1, v.getData());
}
void setUniform(const char *uniform, unsigned int x) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniform1i(pos, x);
}
// Different name to avoid overload ambiguity
void setUniform1f(const char *uniform, float f) {
GLint pos = getUniformLocation(uniform);
if (pos != -1)
glUniform1f(pos, f);
}
GLint getUniformLocation(const char *uniform) const {
UniformsMap::iterator kv = _uniforms->find(uniform);
if (kv == _uniforms->end()) {
GLint ret = glGetUniformLocation(_shaderNo, uniform);
_uniforms->setVal(uniform, ret);
return ret;
} else {
return kv->_value;
}
}
void enableVertexAttribute(const char *attrib, GLuint vbo, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uint32 offset);
void disableVertexAttribute(const char *attrib, int size, const float *data);
template <int r>
void disableVertexAttribute(const char *attrib, const Math::Matrix<r,1> &m) {
disableVertexAttribute(attrib, r, m.getData());
}
VertexAttrib & getAttributeAt(uint32 idx);
VertexAttrib & getAttribute(const char *attrib);
static GLuint createBuffer(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage = GL_STATIC_DRAW);
static Shader* fromFiles(const char *vertex, const char *fragment, const char **attributes);
static Shader* fromFiles(const char *shared, const char **attributes) {
return fromFiles(shared, shared, attributes);
}
static Shader* fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char **attributes);
private:
Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char **attributes);
GLuint _shaderNo;
Common::String _name;
Common::Array<VertexAttrib> _attributes;
UniformsMap *_uniforms;
};
}

View File

@ -0,0 +1,52 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRAPHICS_SYSTEM_HEADERS_H
#define GRAPHICS_SYSTEM_HEADERS_H
#include "common/scummsys.h"
#ifdef USE_GLES2
#define GL_GLEXT_PROTOTYPES
#ifdef IPHONE
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#undef GL_GLEXT_PROTOTYPES
#define glMapBuffer glMapBufferOES
#define glUnmapBuffer glUnmapBufferOES
#define GL_WRITE_ONLY GL_WRITE_ONLY_OES
#ifndef GL_BGRA
# define GL_BGRA GL_BGRA_EXT
#endif
#else
#include <GL/glew.h>
#endif
#endif