diff options
Diffstat (limited to 'backends/platform/android')
| -rw-r--r-- | backends/platform/android/android.cpp | 596 | ||||
| -rw-r--r-- | backends/platform/android/android.mk | 18 | ||||
| -rw-r--r-- | backends/platform/android/asset-archive.cpp | 166 | ||||
| -rw-r--r-- | backends/platform/android/video.cpp | 85 | ||||
| -rw-r--r-- | backends/platform/android/video.h | 128 | 
5 files changed, 663 insertions, 330 deletions
| diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 125fd629d3..6566146313 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -78,14 +78,14 @@  extern "C" {  	void __assert(const char *file, int line, const char *expr) {  		__android_log_assert(expr, LOG_TAG, -							"Assertion failure: '%s' in %s:%d", -							 expr, file, line); +								"Assertion failure: '%s' in %s:%d", +								 expr, file, line);  	}  	void __assert2(const char *file, int line, const char *func, const char *expr) {  		__android_log_assert(expr, LOG_TAG, -							"Assertion failure: '%s' in %s:%d (%s)", -							 expr, file, line, func); +								"Assertion failure: '%s' in %s:%d (%s)", +								 expr, file, line, func);  	}  } @@ -105,6 +105,7 @@ JNIEnv *JNU_GetEnv() {  	JNIEnv *env = 0;  	jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2); +  	if (res != JNI_OK) {  		__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GetEnv() failed: %d", res);  		abort(); @@ -113,15 +114,17 @@ JNIEnv *JNU_GetEnv() {  	return env;  } -static void JNU_ThrowByName(JNIEnv* env, const char* name, const char* msg) { +static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) {  	jclass cls = env->FindClass(name); -	// if cls is NULL, an exception has already been thrown -	if (cls != NULL) + +	// if cls is 0, an exception has already been thrown +	if (cls != 0)  		env->ThrowNew(cls, msg); +  	env->DeleteLocalRef(cls);  } -// floating point. use sparingly. +// floating point. use sparingly  template <class T>  static inline T scalef(T in, float numerator, float denominator) {  	return static_cast<float>(in) * numerator / denominator; @@ -139,10 +142,9 @@ protected:  };  #endif -  #if 0  #define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__) -static const char* getGlErrStr(GLenum error) { +static const char *getGlErrStr(GLenum error) {  	switch (error) {  	case GL_NO_ERROR:		   return "GL_NO_ERROR";  	case GL_INVALID_ENUM:	   return "GL_INVALID_ENUM"; @@ -156,7 +158,7 @@ static const char* getGlErrStr(GLenum error) {  	snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error);  	return buf;  } -static void checkGlError(const char* file, int line) { +static void checkGlError(const char *file, int line) {  	GLenum error = glGetError();  	if (error != GL_NO_ERROR)  		warning("%s:%d: GL error: %s", file, line, getGlErrStr(error)); @@ -167,7 +169,9 @@ static void checkGlError(const char* file, int line) {  class OSystem_Android : public BaseBackend, public PaletteManager {  private: -	jobject _back_ptr;	// back pointer to (java) peer instance +	// back pointer to (java) peer instance +	jobject _back_ptr; +  	jmethodID MID_displayMessageOnOSD;  	jmethodID MID_setWindowCaption;  	jmethodID MID_initBackend; @@ -186,16 +190,16 @@ private:  	bool _force_redraw;  	// Game layer -	GLESPaletteTexture* _game_texture; +	GLESPaletteTexture *_game_texture;  	int _shake_offset;  	Common::Rect _focus_rect;  	// Overlay layer -	GLES4444Texture* _overlay_texture; +	GLES4444Texture *_overlay_texture;  	bool _show_overlay;  	// Mouse layer -	GLESPaletteATexture* _mouse_texture; +	GLESPaletteATexture *_mouse_texture;  	Common::Point _mouse_hotspot;  	int _mouse_targetscale;  	bool _show_mouse; @@ -206,7 +210,7 @@ private:  	bool _timer_thread_exit;  	pthread_t _timer_thread; -	static void* timerThreadFunc(void* arg); +	static void *timerThreadFunc(void *arg);  	bool _enable_zoning;  	bool _virtkeybd_on; @@ -226,9 +230,9 @@ private:  public:  	OSystem_Android(jobject am);  	virtual ~OSystem_Android(); -	bool initJavaHooks(JNIEnv* env, jobject self); +	bool initJavaHooks(JNIEnv *env, jobject self); -	static OSystem_Android* fromJavaObject(JNIEnv* env, jobject obj); +	static OSystem_Android *fromJavaObject(JNIEnv *env, jobject obj);  	virtual void initBackend();  	void addPluginDirectories(Common::FSList &dirs) const;  	void enableZoning(bool enable) { _enable_zoning = enable; } @@ -246,12 +250,19 @@ public:  	virtual bool setGraphicsMode(int mode);  	virtual int getGraphicsMode() const;  	virtual void initSize(uint width, uint height, -				  const Graphics::PixelFormat *format); -	virtual int getScreenChangeID() const { return _screen_changeid; } +							const Graphics::PixelFormat *format); + +	virtual int getScreenChangeID() const { +		return _screen_changeid; +	} +  	virtual int16 getHeight();  	virtual int16 getWidth(); -	virtual PaletteManager *getPaletteManager() { return this; } +	virtual PaletteManager *getPaletteManager() { +		return this; +	} +  protected:  	// PaletteManager API  	virtual void setPalette(const byte *colors, uint start, uint num); @@ -274,18 +285,21 @@ public:  	virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);  	virtual int16 getOverlayHeight();  	virtual int16 getOverlayWidth(); + +	// RGBA 4444  	virtual Graphics::PixelFormat getOverlayFormat() const { -		// RGBA 4444  		Graphics::PixelFormat format; +  		format.bytesPerPixel = 2;  		format.rLoss = 8 - 4;  		format.gLoss = 8 - 4;  		format.bLoss = 8 - 4;  		format.aLoss = 8 - 4; -		format.rShift = 3*4; -		format.gShift = 2*4; -		format.bShift = 1*4; -		format.aShift = 0*4; +		format.rShift = 3 * 4; +		format.gShift = 2 * 4; +		format.bShift = 1 * 4; +		format.aShift = 0 * 4; +  		return format;  	} @@ -321,49 +335,54 @@ public:  	virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);  }; -OSystem_Android::OSystem_Android(jobject am) -	: _back_ptr(0), -	  _screen_changeid(0), -	  _force_redraw(false), -	  _game_texture(NULL), -	  _overlay_texture(NULL), -	  _mouse_texture(NULL), -	  _use_mouse_palette(false), -	  _show_mouse(false), -	  _show_overlay(false), -	  _enable_zoning(false), -	  _savefile(0), -	  _mixer(0), -	  _timer(0), -	  _fsFactory(new POSIXFilesystemFactory()), -	  _asset_archive(new AndroidAssetArchive(am)), -	  _shake_offset(0), -	  _event_queue_lock(createMutex()) { +OSystem_Android::OSystem_Android(jobject am) : +	_back_ptr(0), +	_screen_changeid(0), +	_force_redraw(false), +	_game_texture(0), +	_overlay_texture(0), +	_mouse_texture(0), +	_use_mouse_palette(false), +	_show_mouse(false), +	_show_overlay(false), +	_enable_zoning(false), +	_savefile(0), +	_mixer(0), +	_timer(0), +	_fsFactory(new POSIXFilesystemFactory()), +	_asset_archive(new AndroidAssetArchive(am)), +	_shake_offset(0), +	_event_queue_lock(createMutex()) {  }  OSystem_Android::~OSystem_Android() {  	ENTER("~OSystem_Android()"); +  	delete _game_texture;  	delete _overlay_texture;  	delete _mouse_texture; +  	destroyScummVMSurface(); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	//env->DeleteWeakGlobalRef(_back_ptr);  	env->DeleteGlobalRef(_back_ptr); +  	delete _savefile;  	delete _mixer;  	delete _timer;  	delete _fsFactory;  	delete _asset_archive; +  	deleteMutex(_event_queue_lock);  } -OSystem_Android* OSystem_Android::fromJavaObject(JNIEnv* env, jobject obj) { +OSystem_Android *OSystem_Android::fromJavaObject(JNIEnv *env, jobject obj) {  	jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM); -	return (OSystem_Android*)peer; +	return (OSystem_Android *)peer;  } -bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) { +bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) {  	// weak global ref to allow class to be unloaded  	// ... except dalvik doesn't implement NewWeakGlobalRef (yet)  	//_back_ptr = env->NewWeakGlobalRef(self); @@ -373,7 +392,7 @@ bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) {  #define FIND_METHOD(name, signature) do {						\  		MID_ ## name = env->GetMethodID(cls, #name, signature); \ -		if (MID_ ## name == NULL)								\ +		if (MID_ ## name == 0)									\  			return false;										\  	} while (0) @@ -393,10 +412,11 @@ bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) {  	return true;  } -static void ScummVM_create(JNIEnv* env, jobject self, jobject am) { -	OSystem_Android* cpp_obj = new OSystem_Android(am); +static void ScummVM_create(JNIEnv *env, jobject self, jobject am) { +	OSystem_Android *cpp_obj = new OSystem_Android(am); + +	// Exception already thrown by initJavaHooks?  	if (!cpp_obj->initJavaHooks(env, self)) -		// Exception already thrown by initJavaHooks  		return;  	env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj); @@ -406,56 +426,69 @@ static void ScummVM_create(JNIEnv* env, jobject self, jobject am) {  #endif  } -static void ScummVM_nativeDestroy(JNIEnv* env, jobject self) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	delete cpp_obj;  } -static void ScummVM_audioMixCallback(JNIEnv* env, jobject self, -									 jbyteArray jbuf) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static void ScummVM_audioMixCallback(JNIEnv *env, jobject self, +										jbyteArray jbuf) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	jsize len = env->GetArrayLength(jbuf); -	jbyte* buf = env->GetByteArrayElements(jbuf, NULL); -	if (buf == NULL) { +	jbyte *buf = env->GetByteArrayElements(jbuf, 0); + +	if (buf == 0) {  		warning("Unable to get Java audio byte array. Skipping");  		return;  	} -	Audio::MixerImpl* mixer = -		static_cast<Audio::MixerImpl*>(cpp_obj->getMixer()); + +	Audio::MixerImpl *mixer = +		static_cast<Audio::MixerImpl *>(cpp_obj->getMixer());  	assert(mixer); -	mixer->mixCallback(reinterpret_cast<byte*>(buf), len); +	mixer->mixCallback(reinterpret_cast<byte *>(buf), len); +  	env->ReleaseByteArrayElements(jbuf, buf, 0);  } -static void ScummVM_setConfManInt(JNIEnv* env, jclass cls, -				  jstring key_obj, jint value) { +static void ScummVM_setConfManInt(JNIEnv *env, jclass cls, +									jstring key_obj, jint value) {  	ENTER("setConfManInt(%p, %d)", key_obj, (int)value); -	const char* key = env->GetStringUTFChars(key_obj, NULL); -	if (key == NULL) + +	const char *key = env->GetStringUTFChars(key_obj, 0); + +	if (key == 0)  		return; +  	ConfMan.setInt(key, value); +  	env->ReleaseStringUTFChars(key_obj, key);  } -static void ScummVM_setConfManString(JNIEnv* env, jclass cls, jstring key_obj, -					 jstring value_obj) { +static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj, +										jstring value_obj) {  	ENTER("setConfManStr(%p, %p)", key_obj, value_obj); -	const char* key = env->GetStringUTFChars(key_obj, NULL); -	if (key == NULL) + +	const char *key = env->GetStringUTFChars(key_obj, 0); + +	if (key == 0)  		return; -	const char* value = env->GetStringUTFChars(value_obj, NULL); -	if (value == NULL) { + +	const char *value = env->GetStringUTFChars(value_obj, 0); + +	if (value == 0) {  		env->ReleaseStringUTFChars(key_obj, key);  		return;  	} +  	ConfMan.set(key, value); +  	env->ReleaseStringUTFChars(value_obj, value);  	env->ReleaseStringUTFChars(key_obj, key);  } -void* OSystem_Android::timerThreadFunc(void* arg) { -	OSystem_Android* system = (OSystem_Android*)arg; -	DefaultTimerManager* timer = (DefaultTimerManager*)(system->_timer); +void *OSystem_Android::timerThreadFunc(void *arg) { +	OSystem_Android *system = (OSystem_Android *)arg; +	DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer);  	JNIEnv *env = 0;  	jint res = cached_jvm->AttachCurrentThread(&env, 0); @@ -471,7 +504,7 @@ void* OSystem_Android::timerThreadFunc(void* arg) {  	while (!system->_timer_thread_exit) {  		timer->handler(); -		nanosleep(&tv, NULL); +		nanosleep(&tv, 0);  	}  	res = cached_jvm->DetachCurrentThread(); @@ -481,12 +514,13 @@ void* OSystem_Android::timerThreadFunc(void* arg) {  		abort();  	} -	return NULL; +	return 0;  }  void OSystem_Android::initBackend() {  	ENTER("initBackend()"); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	ConfMan.setInt("autosave_period", 0);  	ConfMan.setInt("FM_medium_quality", true); @@ -496,32 +530,37 @@ void OSystem_Android::initBackend() {  	setupKeymapper();  	// BUG: "transient" ConfMan settings get nuked by the options -	// screen.	Passing the savepath in this way makes it stick +	// screen. Passing the savepath in this way makes it stick  	// (via ConfMan.registerDefault)  	_savefile = new DefaultSaveFileManager(ConfMan.get("savepath"));  	_timer = new DefaultTimerManager(); -	gettimeofday(&_startTime, NULL); +	gettimeofday(&_startTime, 0);  	jint sample_rate = env->CallIntMethod(_back_ptr, MID_audioSampleRate);  	if (env->ExceptionCheck()) {  		warning("Error finding audio sample rate - assuming 11025HZ"); +  		env->ExceptionDescribe();  		env->ExceptionClear(); +  		sample_rate = 11025;  	} +  	_mixer = new Audio::MixerImpl(this, sample_rate);  	_mixer->setReady(true);  	env->CallVoidMethod(_back_ptr, MID_initBackend); +  	if (env->ExceptionCheck()) {  		error("Error in Java initBackend"); +  		env->ExceptionDescribe();  		env->ExceptionClear();  	}  	_timer_thread_exit = false; -	pthread_create(&_timer_thread, NULL, timerThreadFunc, this); +	pthread_create(&_timer_thread, 0, timerThreadFunc, this);  	OSystem::initBackend(); @@ -530,30 +569,39 @@ void OSystem_Android::initBackend() {  void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const {  	ENTER("OSystem_Android::addPluginDirectories()"); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	jobjectArray array =  		(jobjectArray)env->CallObjectMethod(_back_ptr, MID_getPluginDirectories);  	if (env->ExceptionCheck()) {  		warning("Error finding plugin directories"); +  		env->ExceptionDescribe();  		env->ExceptionClear(); +  		return;  	}  	jsize size = env->GetArrayLength(array);  	for (jsize i = 0; i < size; ++i) {  		jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); -		if (path_obj == NULL) + +		if (path_obj == 0)  			continue; -		const char* path = env->GetStringUTFChars(path_obj, NULL); -		if (path == NULL) { + +		const char *path = env->GetStringUTFChars(path_obj, 0); +		if (path == 0) {  			warning("Error getting string characters from plugin directory"); +  			env->ExceptionClear();  			env->DeleteLocalRef(path_obj); +  			continue;  		} +  		dirs.push_back(Common::FSNode(path)); +  		env->ReleaseStringUTFChars(path_obj, path);  		env->DeleteLocalRef(path_obj);  	} @@ -561,12 +609,13 @@ void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const {  bool OSystem_Android::hasFeature(Feature f) {  	return (f == kFeatureCursorHasPalette || -		f == kFeatureVirtualKeyboard || -		f == kFeatureOverlaySupportsAlpha); +			f == kFeatureVirtualKeyboard || +			f == kFeatureOverlaySupportsAlpha);  }  void OSystem_Android::setFeatureState(Feature f, bool enable) {  	ENTER("setFeatureState(%d, %d)", f, enable); +  	switch (f) {  	case kFeatureVirtualKeyboard:  		_virtkeybd_on = enable; @@ -586,11 +635,12 @@ bool OSystem_Android::getFeatureState(Feature f) {  	}  } -const OSystem::GraphicsMode* OSystem_Android::getSupportedGraphicsModes() const { +const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {  	static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { -		{"default", "Default", 1}, -		{0, 0, 0}, +		{ "default", "Default", 1 }, +		{ 0, 0, 0 },  	}; +  	return s_supportedGraphicsModes;  } @@ -615,13 +665,14 @@ int OSystem_Android::getGraphicsMode() const {  void OSystem_Android::setupScummVMSurface() {  	ENTER("setupScummVMSurface"); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface); +  	if (env->ExceptionCheck())  		return;  	// EGL set up with a new surface.  Initialise OpenGLES context. -  	GLESTexture::initGLExtensions();  	// Turn off anything that looks like 3D ;) @@ -630,6 +681,7 @@ void OSystem_Android::setupScummVMSurface() {  	glDisable(GL_LIGHTING);  	glDisable(GL_FOG);  	glDisable(GL_DITHER); +  	glShadeModel(GL_FLAT);  	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); @@ -669,13 +721,13 @@ void OSystem_Android::setupScummVMSurface() {  }  void OSystem_Android::destroyScummVMSurface() { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface);  	// Can't use OpenGLES functions after this  }  void OSystem_Android::initSize(uint width, uint height, -							   const Graphics::PixelFormat *format) { +								const Graphics::PixelFormat *format) {  	ENTER("initSize(%d,%d,%p)", width, height, format);  	_game_texture->allocBuffer(width, height); @@ -700,16 +752,18 @@ int16 OSystem_Android::getWidth() {  	return _game_texture->width();  } -void OSystem_Android::setPalette(const byte* colors, uint start, uint num) { +void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {  	ENTER("setPalette(%p, %u, %u)", colors, start, num);  	if (!_use_mouse_palette)  		_setCursorPalette(colors, start, num); -	byte* palette = _game_texture->palette() + start*3; +	byte *palette = _game_texture->palette() + start * 3; +  	do {  		for (int i = 0; i < 3; ++i)  			palette[i] = colors[i]; +  		palette += 3;  		colors += 4;  	} while (--num); @@ -717,11 +771,15 @@ void OSystem_Android::setPalette(const byte* colors, uint start, uint num) {  void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {  	ENTER("grabPalette(%p, %u, %u)", colors, start, num); -	const byte* palette = _game_texture->palette_const() + start*3; + +	const byte *palette = _game_texture->palette_const() + start * 3; +  	do {  		for (int i = 0; i < 3; ++i)  			colors[i] = palette[i]; -		colors[3] = 0xff;  // alpha + +		// alpha +		colors[3] = 0xff;  		palette += 3;  		colors += 4; @@ -729,9 +787,9 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {  }  void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, -					   int x, int y, int w, int h) { +										int x, int y, int w, int h) {  	ENTER("copyRectToScreen(%p, %d, %d, %d, %d, %d)", -		  buf, pitch, x, y, w, h); +			buf, pitch, x, y, w, h);  	_game_texture->updateBuffer(x, y, w, h, buf, pitch);  } @@ -740,9 +798,9 @@ void OSystem_Android::updateScreen() {  	//ENTER("updateScreen()");  	if (!_force_redraw && -		!_game_texture->dirty() && -		!_overlay_texture->dirty() && -		!_mouse_texture->dirty()) +			!_game_texture->dirty() && +			!_overlay_texture->dirty() && +			!_mouse_texture->dirty())  		return;  	_force_redraw = false; @@ -750,9 +808,9 @@ void OSystem_Android::updateScreen() {  	glPushMatrix();  	if (_shake_offset != 0 || -		(!_focus_rect.isEmpty() && -		 !Common::Rect(_game_texture->width(), -					   _game_texture->height()).contains(_focus_rect))) { +			(!_focus_rect.isEmpty() && +			!Common::Rect(_game_texture->width(), +							_game_texture->height()).contains(_focus_rect))) {  		// These are the only cases where _game_texture doesn't  		// cover the entire screen.  		glClearColorx(0, 0, 0, 1 << 16); @@ -764,18 +822,19 @@ void OSystem_Android::updateScreen() {  	if (_focus_rect.isEmpty()) {  		_game_texture->drawTexture(0, 0, -								   _egl_surface_width, _egl_surface_height); +									_egl_surface_width, _egl_surface_height);  	} else {  		glPushMatrix();  		glScalex(xdiv(_egl_surface_width, _focus_rect.width()), -				 xdiv(_egl_surface_height, _focus_rect.height()), -				 1 << 16); +					xdiv(_egl_surface_height, _focus_rect.height()), +					1 << 16);  		glTranslatex(-_focus_rect.left << 16, -_focus_rect.top << 16, 0);  		glScalex(xdiv(_game_texture->width(), _egl_surface_width), -				 xdiv(_game_texture->height(), _egl_surface_height), -				 1 << 16); +					xdiv(_game_texture->height(), _egl_surface_height), +					1 << 16); +  		_game_texture->drawTexture(0, 0, -								   _egl_surface_width, _egl_surface_height); +									_egl_surface_width, _egl_surface_height);  		glPopMatrix();  	} @@ -783,8 +842,8 @@ void OSystem_Android::updateScreen() {  	if (_show_overlay) {  		_overlay_texture->drawTexture(0, 0, -									  _egl_surface_width, -									  _egl_surface_height); +										_egl_surface_width, +										_egl_surface_height);  		CHECK_GL_ERROR();  	} @@ -792,11 +851,12 @@ void OSystem_Android::updateScreen() {  		glPushMatrix();  		glTranslatex(-_mouse_hotspot.x << 16, -					 -_mouse_hotspot.y << 16, -					 0); +						-_mouse_hotspot.y << 16, +						0);  		// Scale up ScummVM -> OpenGL (pixel) coordinates  		int texwidth, texheight; +  		if (_show_overlay) {  			texwidth = getOverlayWidth();  			texheight = getOverlayHeight(); @@ -804,15 +864,16 @@ void OSystem_Android::updateScreen() {  			texwidth = getWidth();  			texheight = getHeight();  		} +  		glScalex(xdiv(_egl_surface_width, texwidth), -				 xdiv(_egl_surface_height, texheight), -				 1 << 16); +					xdiv(_egl_surface_height, texheight), +					1 << 16);  		// Note the extra half texel to position the mouse in  		// the middle of the x,y square:  		const Common::Point& mouse = getEventManager()->getMousePos();  		glTranslatex((mouse.x << 16) | 1 << 15, -					 (mouse.y << 16) | 1 << 15, 0); +						(mouse.y << 16) | 1 << 15, 0);  		// Mouse targetscale just seems to make the cursor way  		// too big :/ @@ -828,7 +889,7 @@ void OSystem_Android::updateScreen() {  	CHECK_GL_ERROR(); -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) {  		// Context lost -> need to reinit GL  		destroyScummVMSurface(); @@ -838,18 +899,22 @@ void OSystem_Android::updateScreen() {  Graphics::Surface *OSystem_Android::lockScreen() {  	ENTER("lockScreen()"); -	Graphics::Surface* surface = _game_texture->surface(); + +	Graphics::Surface *surface = _game_texture->surface();  	assert(surface->pixels); +  	return surface;  }  void OSystem_Android::unlockScreen() {  	ENTER("unlockScreen()"); +  	assert(_game_texture->dirty());  }  void OSystem_Android::setShakePos(int shake_offset) {  	ENTER("setShakePos(%d)", shake_offset); +  	if (_shake_offset != shake_offset) {  		_shake_offset = shake_offset;  		_force_redraw = true; @@ -858,13 +923,15 @@ void OSystem_Android::setShakePos(int shake_offset) {  void OSystem_Android::fillScreen(uint32 col) {  	ENTER("fillScreen(%u)", col); +  	assert(col < 256);  	_game_texture->fillBuffer(col);  }  void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {  	ENTER("setFocusRectangle(%d,%d,%d,%d)", -		  rect.left, rect.top, rect.right, rect.bottom); +			rect.left, rect.top, rect.right, rect.bottom); +  	if (_enable_zoning) {  		_focus_rect = rect;  		_force_redraw = true; @@ -873,6 +940,7 @@ void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {  void OSystem_Android::clearFocusRectangle() {  	ENTER("clearFocusRectangle()"); +  	if (_enable_zoning) {  		_focus_rect = Common::Rect();  		_force_redraw = true; @@ -881,18 +949,21 @@ void OSystem_Android::clearFocusRectangle() {  void OSystem_Android::showOverlay() {  	ENTER("showOverlay()"); +  	_show_overlay = true;  	_force_redraw = true;  }  void OSystem_Android::hideOverlay() {  	ENTER("hideOverlay()"); +  	_show_overlay = false;  	_force_redraw = true;  }  void OSystem_Android::clearOverlay() {  	ENTER("clearOverlay()"); +  	_overlay_texture->fillBuffer(0);  	// Shouldn't need this, but works around a 'blank screen' bug on Nexus1 @@ -901,23 +972,29 @@ void OSystem_Android::clearOverlay() {  void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {  	ENTER("grabOverlay(%p, %d)", buf, pitch); +  	// We support overlay alpha blending, so the pixel data here  	// shouldn't actually be used.	Let's fill it with zeros, I'm sure  	// it will be fine... -	const Graphics::Surface* surface = _overlay_texture->surface_const(); +	const Graphics::Surface *surface = _overlay_texture->surface_const();  	assert(surface->bytesPerPixel == sizeof(buf[0])); +  	int h = surface->h; +  	do {  		memset(buf, 0, surface->w * sizeof(buf[0])); -		buf += pitch;  // This 'pitch' is pixels not bytes + +		// This 'pitch' is pixels not bytes +		buf += pitch;  	} while (--h);  }  void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, -					int x, int y, int w, int h) { +										int x, int y, int w, int h) {  	ENTER("copyRectToOverlay(%p, %d, %d, %d, %d, %d)", -		 buf, pitch, x, y, w, h); -	const Graphics::Surface* surface = _overlay_texture->surface_const(); +			buf, pitch, x, y, w, h); + +	const Graphics::Surface *surface = _overlay_texture->surface_const();  	assert(surface->bytesPerPixel == sizeof(buf[0]));  	// This 'pitch' is pixels not bytes @@ -937,37 +1014,43 @@ int16 OSystem_Android::getOverlayWidth() {  bool OSystem_Android::showMouse(bool visible) {  	ENTER("showMouse(%d)", visible); +  	_show_mouse = visible; +  	return true;  }  void OSystem_Android::warpMouse(int x, int y) {  	ENTER("warpMouse(%d, %d)", x, y); +  	// We use only the eventmanager's idea of the current mouse  	// position, so there is nothing extra to do here.  }  void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, -					 int hotspotX, int hotspotY, -					 uint32 keycolor, int cursorTargetScale, -					 const Graphics::PixelFormat *format) { +										int hotspotX, int hotspotY, +										uint32 keycolor, int cursorTargetScale, +										const Graphics::PixelFormat *format) {  	ENTER("setMouseCursor(%p, %u, %u, %d, %d, %d, %d, %p)", -		  buf, w, h, hotspotX, hotspotY, (int)keycolor, cursorTargetScale, -		  format); +			buf, w, h, hotspotX, hotspotY, (int)keycolor, cursorTargetScale, +			format);  	assert(keycolor < 256);  	_mouse_texture->allocBuffer(w, h);  	// Update palette alpha based on keycolor -	byte* palette = _mouse_texture->palette(); +	byte *palette = _mouse_texture->palette();  	int i = 256; +  	do {  		palette[3] = 0xff;  		palette += 4;  	} while (--i); +  	palette = _mouse_texture->palette(); -	palette[keycolor*4 + 3] = 0x00; +	palette[keycolor * 4 + 3] = 0x00; +  	_mouse_texture->updateBuffer(0, 0, w, h, buf, w);  	_mouse_hotspot = Common::Point(hotspotX, hotspotY); @@ -975,11 +1058,13 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,  }  void OSystem_Android::_setCursorPalette(const byte *colors, -					uint start, uint num) { -	byte* palette = _mouse_texture->palette() + start*4; +										uint start, uint num) { +	byte *palette = _mouse_texture->palette() + start * 4; +  	do {  		for (int i = 0; i < 3; ++i)  			palette[i] = colors[i]; +  		// Leave alpha untouched to preserve keycolor  		palette += 4; @@ -988,14 +1073,16 @@ void OSystem_Android::_setCursorPalette(const byte *colors,  }  void OSystem_Android::setCursorPalette(const byte *colors, -					   uint start, uint num) { +										uint start, uint num) {  	ENTER("setCursorPalette(%p, %u, %u)", colors, start, num); +  	_setCursorPalette(colors, start, num);  	_use_mouse_palette = true;  }  void OSystem_Android::disableCursorPalette(bool disable) {  	ENTER("disableCursorPalette(%d)", disable); +  	_use_mouse_palette = !disable;  } @@ -1006,17 +1093,19 @@ void OSystem_Android::setupKeymapper() {  	Keymapper *mapper = getEventManager()->getKeymapper();  	HardwareKeySet *keySet = new HardwareKeySet(); +  	keySet->addHardwareKey(  		new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)",  				kTriggerLeftKeyType,  				kVirtualKeyboardActionType)); +  	mapper->registerHardwareKeySet(keySet);  	Keymap *globalMap = new Keymap("global");  	Action *act;  	act = new Action(globalMap, "VIRT", "Display keyboard", -			 kVirtualKeyboardActionType); +						kVirtualKeyboardActionType);  	act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0));  	mapper->addGlobalKeymap(globalMap); @@ -1027,11 +1116,14 @@ void OSystem_Android::setupKeymapper() {  bool OSystem_Android::pollEvent(Common::Event &event) {  	//ENTER("pollEvent()"); +  	lockMutex(_event_queue_lock); +  	if (_event_queue.empty()) {  		unlockMutex(_event_queue_lock);  		return false;  	} +  	event = _event_queue.pop();  	unlockMutex(_event_queue_lock); @@ -1048,26 +1140,27 @@ bool OSystem_Android::pollEvent(Common::Event &event) {  	case Common::EVENT_WHEELDOWN:  	case Common::EVENT_MBUTTONDOWN:  	case Common::EVENT_MBUTTONUP: { -		if (event.kbd.flags == 1) { // relative mouse hack +		// relative mouse hack +		if (event.kbd.flags == 1) {  			// Relative (trackball) mouse hack.  			const Common::Point& mouse_pos =  				getEventManager()->getMousePos();  			event.mouse.x += mouse_pos.x;  			event.mouse.y += mouse_pos.y;  			event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ? -								 getOverlayWidth() : getWidth()); +									getOverlayWidth() : getWidth());  			event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ? -								 getOverlayHeight() : getHeight()); +									getOverlayHeight() : getHeight());  		} else {  			// Touchscreen events need to be converted  			// from device to game coords first. -			const GLESTexture* tex = _show_overlay -				? static_cast<GLESTexture*>(_overlay_texture) -				: static_cast<GLESTexture*>(_game_texture); +			const GLESTexture *tex = _show_overlay +				? static_cast<GLESTexture *>(_overlay_texture) +				: static_cast<GLESTexture *>(_game_texture);  			event.mouse.x = scalef(event.mouse.x, tex->width(), -								   _egl_surface_width); +									_egl_surface_width);  			event.mouse.y = scalef(event.mouse.y, tex->height(), -								   _egl_surface_height); +									_egl_surface_height);  			event.mouse.x -= _shake_offset;  		}  		break; @@ -1090,32 +1183,33 @@ void OSystem_Android::pushEvent(const Common::Event& event) {  	// Try to combine multiple queued mouse move events  	if (event.type == Common::EVENT_MOUSEMOVE && -		!_event_queue.empty() && -		_event_queue.back().type == Common::EVENT_MOUSEMOVE) { -	  Common::Event tail = _event_queue.back(); -	  if (event.kbd.flags) { -		// relative movement hack -		tail.mouse.x += event.mouse.x; -		tail.mouse.y += event.mouse.y; -	  } else { -		// absolute position -		tail.kbd.flags = 0;	 // clear relative flag -		tail.mouse.x = event.mouse.x; -		tail.mouse.y = event.mouse.y; -	  } -	} -	else +			!_event_queue.empty() && +			_event_queue.back().type == Common::EVENT_MOUSEMOVE) { +		Common::Event tail = _event_queue.back(); +		if (event.kbd.flags) { +			// relative movement hack +			tail.mouse.x += event.mouse.x; +			tail.mouse.y += event.mouse.y; +		} else { +			// absolute position, clear relative flag +			tail.kbd.flags = 0; +			tail.mouse.x = event.mouse.x; +			tail.mouse.y = event.mouse.y; +		} +	} else {  	  _event_queue.push(event); +	}  	unlockMutex(_event_queue_lock);  } -static void ScummVM_pushEvent(JNIEnv* env, jobject self, jobject java_event) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	Common::Event event;  	event.type = (Common::EventType)env->GetIntField(java_event, -							 FID_Event_type); +														FID_Event_type); +  	event.synthetic =  		env->GetBooleanField(java_event, FID_Event_synthetic); @@ -1157,7 +1251,9 @@ static void ScummVM_pushEvent(JNIEnv* env, jobject self, jobject java_event) {  uint32 OSystem_Android::getMillis() {  	timeval curTime; -	gettimeofday(&curTime, NULL); + +	gettimeofday(&curTime, 0); +  	return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \  			((curTime.tv_usec - _startTime.tv_usec) / 1000));  } @@ -1172,26 +1268,31 @@ OSystem::MutexRef OSystem_Android::createMutex() {  	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  	pthread_mutex_t *mutex = new pthread_mutex_t; +  	if (pthread_mutex_init(mutex, &attr) != 0) {  		warning("pthread_mutex_init() failed"); +  		delete mutex; -		return NULL; + +		return 0;  	} +  	return (MutexRef)mutex;  }  void OSystem_Android::lockMutex(MutexRef mutex) { -	if (pthread_mutex_lock((pthread_mutex_t*)mutex) != 0) +	if (pthread_mutex_lock((pthread_mutex_t *)mutex) != 0)  		warning("pthread_mutex_lock() failed");  }  void OSystem_Android::unlockMutex(MutexRef mutex) { -	if (pthread_mutex_unlock((pthread_mutex_t*)mutex) != 0) +	if (pthread_mutex_unlock((pthread_mutex_t *)mutex) != 0)  		warning("pthread_mutex_unlock() failed");  }  void OSystem_Android::deleteMutex(MutexRef mutex) { -	pthread_mutex_t* m = (pthread_mutex_t*)mutex; +	pthread_mutex_t *m = (pthread_mutex_t *)mutex; +  	if (pthread_mutex_destroy(m) != 0)  		warning("pthread_mutex_destroy() failed");  	else @@ -1202,41 +1303,54 @@ void OSystem_Android::quit() {  	ENTER("quit()");  	_timer_thread_exit = true; -	pthread_join(_timer_thread, NULL); +	pthread_join(_timer_thread, 0);  }  void OSystem_Android::setWindowCaption(const char *caption) {  	ENTER("setWindowCaption(%s)", caption); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	jstring java_caption = env->NewStringUTF(caption);  	env->CallVoidMethod(_back_ptr, MID_setWindowCaption, java_caption); +  	if (env->ExceptionCheck()) {  		warning("Failed to set window caption"); +  		env->ExceptionDescribe();  		env->ExceptionClear();  	} +  	env->DeleteLocalRef(java_caption);  }  void OSystem_Android::displayMessageOnOSD(const char *msg) {  	ENTER("displayMessageOnOSD(%s)", msg); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv();  	jstring java_msg = env->NewStringUTF(msg); +  	env->CallVoidMethod(_back_ptr, MID_displayMessageOnOSD, java_msg); +  	if (env->ExceptionCheck()) {  		warning("Failed to display OSD message"); +  		env->ExceptionDescribe();  		env->ExceptionClear();  	} +  	env->DeleteLocalRef(java_msg);  }  void OSystem_Android::showVirtualKeyboard(bool enable) {  	ENTER("showVirtualKeyboard(%d)", enable); -	JNIEnv* env = JNU_GetEnv(); + +	JNIEnv *env = JNU_GetEnv(); +  	env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable); +  	if (env->ExceptionCheck()) {  		error("Error trying to show virtual keyboard"); +  		env->ExceptionDescribe();  		env->ExceptionClear();  	} @@ -1259,7 +1373,8 @@ Common::TimerManager *OSystem_Android::getTimerManager() {  void OSystem_Android::getTimeAndDate(TimeDate &td) const {  	struct tm tm; -	const time_t curTime = time(NULL); +	const time_t curTime = time(0); +  	localtime_r(&curTime, &tm);  	td.tm_sec = tm.tm_sec;  	td.tm_min = tm.tm_min; @@ -1274,28 +1389,33 @@ FilesystemFactory *OSystem_Android::getFilesystemFactory() {  }  void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, -						int priority) { +												int priority) {  	s.add("ASSET", _asset_archive, priority, false); -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	jobjectArray array =  		(jobjectArray)env->CallObjectMethod(_back_ptr, MID_getSysArchives); +  	if (env->ExceptionCheck()) {  		warning("Error finding system archive path"); +  		env->ExceptionDescribe();  		env->ExceptionClear(); +  		return;  	}  	jsize size = env->GetArrayLength(array);  	for (jsize i = 0; i < size; ++i) {  		jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); -		const char* path = env->GetStringUTFChars(path_obj, NULL); -		if (path != NULL) { +		const char *path = env->GetStringUTFChars(path_obj, 0); + +		if (path != 0) {  			s.addDirectory(path, path, priority);  			env->ReleaseStringUTFChars(path_obj, path);  		} +  		env->DeleteLocalRef(path_obj);  	}  } @@ -1316,8 +1436,8 @@ void OSystem_Android::logMessage(LogMessageType::Type type, const char *message)  	}  } -static jint ScummVM_scummVMMain(JNIEnv* env, jobject self, jobjectArray args) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	const int MAX_NARGS = 32;  	int res = -1; @@ -1325,42 +1445,58 @@ static jint ScummVM_scummVMMain(JNIEnv* env, jobject self, jobjectArray args) {  	int argc = env->GetArrayLength(args);  	if (argc > MAX_NARGS) {  		JNU_ThrowByName(env, "java/lang/IllegalArgumentException", -				"too many arguments"); +						"too many arguments");  		return 0;  	} -	char* argv[MAX_NARGS]; -	int nargs;	// note use in cleanup loop below +	char *argv[MAX_NARGS]; + +	// note use in cleanup loop below +	int nargs; +  	for (nargs = 0; nargs < argc; ++nargs) {  		jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); -		if (arg == NULL) { -			argv[nargs] = NULL; + +		if (arg == 0) { +			argv[nargs] = 0;  		} else { -			const char* cstr = env->GetStringUTFChars(arg, NULL); -			argv[nargs] = const_cast<char*>(cstr); -			if (cstr == NULL) -				goto cleanup;  // exception already thrown +			const char *cstr = env->GetStringUTFChars(arg, 0); + +			argv[nargs] = const_cast<char *>(cstr); + +			// exception already thrown? +			if (cstr == 0) +				goto cleanup;  		} +  		env->DeleteLocalRef(arg);  	}  	g_system = cpp_obj;  	assert(g_system); +  	__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, -				"Entering scummvm_main with %d args", argc); +						"Entering scummvm_main with %d args", argc); +  	res = scummvm_main(argc, argv); +  	__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Exiting scummvm_main"); +  	g_system->quit();  cleanup:  	nargs--; +  	for (int i = 0; i < nargs; ++i) { -		if (argv[i] == NULL) +		if (argv[i] == 0)  			continue; +  		jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); -		if (arg == NULL) -			// Exception already thrown + +		// Exception already thrown? +		if (arg == 0)  			return res; +  		env->ReleaseStringUTFChars(arg, argv[i]);  		env->DeleteLocalRef(arg);  	} @@ -1370,93 +1506,105 @@ cleanup:  #ifdef DYNAMIC_MODULES  void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { -	OSystem_Android* g_system_android = (OSystem_Android*)g_system; +	OSystem_Android *g_system_android = (OSystem_Android *)g_system;  	g_system_android->addPluginDirectories(dirs);  }  #endif -static void ScummVM_enableZoning(JNIEnv* env, jobject self, jboolean enable) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	cpp_obj->enableZoning(enable);  } -static void ScummVM_setSurfaceSize(JNIEnv* env, jobject self, -								   jint width, jint height) { -	OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +static void ScummVM_setSurfaceSize(JNIEnv *env, jobject self, +									jint width, jint height) { +	OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);  	cpp_obj->setSurfaceSize(width, height);  }  const static JNINativeMethod gMethods[] = {  	{ "create", "(Landroid/content/res/AssetManager;)V", -	  (void*)ScummVM_create }, -	{ "nativeDestroy", "()V", (void*)ScummVM_nativeDestroy }, +		(void *)ScummVM_create }, +	{ "nativeDestroy", "()V", +		(void *)ScummVM_nativeDestroy },  	{ "scummVMMain", "([Ljava/lang/String;)I", -	  (void*)ScummVM_scummVMMain }, +	 	(void *)ScummVM_scummVMMain },  	{ "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", -	  (void*)ScummVM_pushEvent }, +		(void *)ScummVM_pushEvent },  	{ "audioMixCallback", "([B)V", -	  (void*)ScummVM_audioMixCallback }, +		(void *)ScummVM_audioMixCallback },  	{ "setConfMan", "(Ljava/lang/String;I)V", -	  (void*)ScummVM_setConfManInt }, +		(void *)ScummVM_setConfManInt },  	{ "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", -	  (void*)ScummVM_setConfManString }, +		(void *)ScummVM_setConfManString },  	{ "enableZoning", "(Z)V", -	  (void*)ScummVM_enableZoning }, +		(void *)ScummVM_enableZoning },  	{ "setSurfaceSize", "(II)V", -	  (void*)ScummVM_setSurfaceSize }, +		(void *)ScummVM_setSurfaceSize },  };  JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM* jvm, void* reserved) { +JNI_OnLoad(JavaVM *jvm, void *reserved) {  	cached_jvm = jvm; -	JNIEnv* env; -	if (jvm->GetEnv((void**)&env, JNI_VERSION_1_2)) +	JNIEnv *env; + +	if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))  		return JNI_ERR;  	jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM"); -	if (cls == NULL) +	if (cls == 0)  		return JNI_ERR; +  	if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0)  		return JNI_ERR;  	FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J"); -	if (FID_ScummVM_nativeScummVM == NULL) +	if (FID_ScummVM_nativeScummVM == 0)  		return JNI_ERR;  	jclass event = env->FindClass("org/inodes/gus/scummvm/Event"); -	if (event == NULL) +	if (event == 0)  		return JNI_ERR; +  	FID_Event_type = env->GetFieldID(event, "type", "I"); -	if (FID_Event_type == NULL) +	if (FID_Event_type == 0)  		return JNI_ERR; +  	FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z"); -	if (FID_Event_synthetic == NULL) +	if (FID_Event_synthetic == 0)  		return JNI_ERR; +  	FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I"); -	if (FID_Event_kbd_keycode == NULL) +	if (FID_Event_kbd_keycode == 0)  		return JNI_ERR; +  	FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I"); -	if (FID_Event_kbd_ascii == NULL) +	if (FID_Event_kbd_ascii == 0)  		return JNI_ERR; +  	FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I"); -	if (FID_Event_kbd_flags == NULL) +	if (FID_Event_kbd_flags == 0)  		return JNI_ERR; +  	FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I"); -	if (FID_Event_mouse_x == NULL) +	if (FID_Event_mouse_x == 0)  		return JNI_ERR; +  	FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I"); -	if (FID_Event_mouse_y == NULL) +	if (FID_Event_mouse_y == 0)  		return JNI_ERR; +  	FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z"); -	if (FID_Event_mouse_relative == NULL) +	if (FID_Event_mouse_relative == 0)  		return JNI_ERR;  	cls = env->FindClass("java/lang/Object"); -	if (cls == NULL) +	if (cls == 0)  		return JNI_ERR; +  	MID_Object_wait = env->GetMethodID(cls, "wait", "()V"); -	if (MID_Object_wait == NULL) +	if (MID_Object_wait == 0)  		return JNI_ERR;  	return JNI_VERSION_1_2; diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index a99078581e..1bc3c3d21a 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -109,12 +109,12 @@ $(FILE_DEX_PLUGIN): $(CLASSES_PLUGIN)  $(PATH_BUILD)/%/AndroidManifest.xml $(PATH_STAGE_PREFIX).%/res/values/strings.xml: $(PATH_DIST)/mkmanifest.pl $(srcdir)/configure $(PATH_DIST)/AndroidManifest.xml  	$(PATH_DIST)/mkmanifest.pl --id=$* --configure=$(srcdir)/configure \ -	  --version-name=$(VERSION) \ -	  --version-code=$(ANDROID_PLUGIN_VERSIONCODE) \ -	  --stringres=$(PATH_STAGE_PREFIX).$*/res/values/strings.xml \ -	  --manifest=$(PATH_BUILD)/$*/AndroidManifest.xml \ -	  --master-manifest=$(PATH_DIST)/AndroidManifest.xml \ -	  --unpacklib=mylib/armeabi/lib$*.so +		--version-name=$(VERSION) \ +		--version-code=$(ANDROID_PLUGIN_VERSIONCODE) \ +		--stringres=$(PATH_STAGE_PREFIX).$*/res/values/strings.xml \ +		--manifest=$(PATH_BUILD)/$*/AndroidManifest.xml \ +		--master-manifest=$(PATH_DIST)/AndroidManifest.xml \ +		--unpacklib=mylib/armeabi/lib$*.so  $(PATH_STAGE_PREFIX).%/res/drawable/scummvm.png: $(PATH_RESOURCES)/drawable/scummvm.png  	@$(MKDIR) -p $(@D) @@ -165,7 +165,7 @@ androidrelease: $(addprefix release/, $(APK_MAIN) $(APK_PLUGINS))  androidtest: $(APK_MAIN) $(APK_PLUGINS)  	@set -e; for apk in $^; do \ -	  $(ADB) install -r $$apk; \ +		$(ADB) install -r $$apk; \  	done  	$(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker @@ -173,7 +173,9 @@ androidtest: $(APK_MAIN) $(APK_PLUGINS)  androiddistdebug: all  	$(MKDIR) debug  	$(CP) $(APK_MAIN) $(APK_PLUGINS) debug/ -	for i in $(DIST_FILES_DOCS); do sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; done +	for i in $(DIST_FILES_DOCS); do \ +		sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; \ +	done  .PHONY: androidrelease androidtest diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index bd32847f6a..3197c75b82 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -38,7 +38,7 @@  #include "backends/platform/android/asset-archive.h" -extern JNIEnv* JNU_GetEnv(); +extern JNIEnv *JNU_GetEnv();  // Must match android.content.res.AssetManager.ACCESS_*  const jint ACCESS_UNKNOWN = 0; @@ -47,23 +47,43 @@ const jint ACCESS_RANDOM = 1;  // This might be useful to someone else.  Assumes markSupported() == true.  class JavaInputStream : public Common::SeekableReadStream {  public: -	JavaInputStream(JNIEnv* env, jobject is); +	JavaInputStream(JNIEnv *env, jobject is);  	virtual ~JavaInputStream(); -	virtual bool eos() const { return _eos; } -	virtual bool err() const { return _err; } -	virtual void clearErr() { _eos = _err = false; } + +	virtual bool eos() const { +		return _eos; +	} + +	virtual bool err() const { +		return _err; +	} + +	virtual void clearErr() { +		_eos = _err = false; +	} +  	virtual uint32 read(void *dataPtr, uint32 dataSize); -	virtual int32 pos() const { return _pos; } -	virtual int32 size() const { return _len; } + +	virtual int32 pos() const { +		return _pos; +	} + +	virtual int32 size() const { +		return _len; +	} +  	virtual bool seek(int32 offset, int whence = SEEK_SET); +  private: -	void close(JNIEnv* env); +	void close(JNIEnv *env); +  	jmethodID MID_mark;  	jmethodID MID_available;  	jmethodID MID_close;  	jmethodID MID_read;  	jmethodID MID_reset;  	jmethodID MID_skip; +  	jobject _input_stream;  	jsize _buflen;  	jbyteArray _buf; @@ -73,8 +93,10 @@ private:  	bool _err;  }; -JavaInputStream::JavaInputStream(JNIEnv* env, jobject is) : -	_eos(false), _err(false), _pos(0) +JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : +	_eos(false), +	_err(false), +	_pos(0)  {  	_input_stream = env->NewGlobalRef(is);  	_buflen = 8192; @@ -97,53 +119,61 @@ JavaInputStream::JavaInputStream(JNIEnv* env, jobject is) :  	// Mark start of stream, so we can reset back to it.  	// readlimit is set to something bigger than anything we might  	// want to seek within. -	env->CallVoidMethod(_input_stream, MID_mark, 10*1024*1024); +	env->CallVoidMethod(_input_stream, MID_mark, 10 * 1024 * 1024);  	_len = env->CallIntMethod(_input_stream, MID_available);  }  JavaInputStream::~JavaInputStream() { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	close(env); +  	env->DeleteGlobalRef(_buf);  	env->DeleteGlobalRef(_input_stream);  } -void JavaInputStream::close(JNIEnv* env) { +void JavaInputStream::close(JNIEnv *env) {  	env->CallVoidMethod(_input_stream, MID_close); +  	if (env->ExceptionCheck())  		env->ExceptionClear();  }  uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	if (_buflen < dataSize) {  		_buflen = dataSize; +	  		env->DeleteGlobalRef(_buf);  		_buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen)));  	}  	jint ret = env->CallIntMethod(_input_stream, MID_read, _buf, 0, dataSize); +  	if (env->ExceptionCheck()) {  		warning("Exception during JavaInputStream::read(%p, %d)",  				dataPtr, dataSize); +  		env->ExceptionDescribe();  		env->ExceptionClear(); +  		_err = true;  		ret = -1;  	} else if (ret == -1) {  		_eos = true;  		ret = 0;  	} else { -		env->GetByteArrayRegion(_buf, 0, ret, static_cast<jbyte*>(dataPtr)); +		env->GetByteArrayRegion(_buf, 0, ret, static_cast<jbyte *>(dataPtr));  		_pos += ret;  	} +  	return ret;  }  bool JavaInputStream::seek(int32 offset, int whence) { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	uint32 newpos; +  	switch (whence) {  	case SEEK_SET:  		newpos = offset; @@ -165,37 +195,47 @@ bool JavaInputStream::seek(int32 offset, int whence) {  	} else {  		// Can't skip backwards, so jump back to start and skip from there.  		env->CallVoidMethod(_input_stream, MID_reset); +  		if (env->ExceptionCheck()) {  			warning("Failed to rewind to start of asset stream"); +  			env->ExceptionDescribe();  			env->ExceptionClear(); +  			return false;  		} +  		_pos = 0;  		skip_bytes = newpos;  	}  	while (skip_bytes > 0) {  		jlong ret = env->CallLongMethod(_input_stream, MID_skip, skip_bytes); +  		if (env->ExceptionCheck()) {  			warning("Failed to skip %ld bytes into asset stream",  					static_cast<long>(skip_bytes)); +  			env->ExceptionDescribe();  			env->ExceptionClear(); +  			return false;  		} else if (ret == 0) {  			warning("InputStream->skip(%ld) didn't skip any bytes. Aborting seek.",  					static_cast<long>(skip_bytes)); -			return false;  // No point looping forever... + +			// No point looping forever... +			return false;  		} +  		_pos += ret;  		skip_bytes -= ret;  	} +  	_eos = false;  	return true;  } -  // Must match android.content.res.AssetFileDescriptor.UNKNOWN_LENGTH  const jlong UNKNOWN_LENGTH = -1; @@ -203,17 +243,36 @@ const jlong UNKNOWN_LENGTH = -1;  // worth optimising for.  class AssetFdReadStream : public Common::SeekableReadStream {  public: -	AssetFdReadStream(JNIEnv* env, jobject assetfd); +	AssetFdReadStream(JNIEnv *env, jobject assetfd);  	virtual ~AssetFdReadStream(); -	virtual bool eos() const { return _eos; } -	virtual bool err() const { return _err; } -	virtual void clearErr() { _eos = _err = false; } + +	virtual bool eos() const { +		return _eos; +	} + +	virtual bool err() const { +		return _err; +	} + +	virtual void clearErr() { +		_eos = _err = false; +	} +  	virtual uint32 read(void *dataPtr, uint32 dataSize); -	virtual int32 pos() const { return _pos; } -	virtual int32 size() const { return _declared_len; } + +	virtual int32 pos() const { +		return _pos; +	} + +	virtual int32 size() const { +		return _declared_len; +	} +  	virtual bool seek(int32 offset, int whence = SEEK_SET); +  private: -	void close(JNIEnv* env); +	void close(JNIEnv *env); +  	int _fd;  	jmethodID MID_close;  	jobject _assetfd; @@ -224,8 +283,10 @@ private:  	bool _err;  }; -AssetFdReadStream::AssetFdReadStream(JNIEnv* env, jobject assetfd) : -	_eos(false), _err(false), _pos(0) +AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : +	_eos(false), +	_err(false), +	_pos(0)  {  	_assetfd = env->NewGlobalRef(assetfd); @@ -248,17 +309,21 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv* env, jobject assetfd) :  	assert(MID_getFileDescriptor);  	jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor);  	assert(javafd); +  	jclass fd_cls = env->GetObjectClass(javafd);  	jfieldID FID_descriptor = env->GetFieldID(fd_cls, "descriptor", "I");  	assert(FID_descriptor); +  	_fd = env->GetIntField(javafd, FID_descriptor);  }  AssetFdReadStream::~AssetFdReadStream() { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	env->CallVoidMethod(_assetfd, MID_close); +  	if (env->ExceptionCheck())  		env->ExceptionClear(); +  	env->DeleteGlobalRef(_assetfd);  } @@ -268,13 +333,16 @@ uint32 AssetFdReadStream::read(void *dataPtr, uint32 dataSize) {  		if (dataSize > cap)  			dataSize = cap;  	} +  	int ret = ::read(_fd, dataPtr, dataSize); +  	if (ret == 0)  		_eos = true;  	else if (ret == -1)  		_err = true;  	else  		_pos += ret; +  	return ret;  } @@ -282,42 +350,49 @@ bool AssetFdReadStream::seek(int32 offset, int whence) {  	if (whence == SEEK_SET) {  		if (_declared_len != UNKNOWN_LENGTH && offset > _declared_len)  			offset = _declared_len; +  		offset += _start_off;  	} else if (whence == SEEK_END && _declared_len != UNKNOWN_LENGTH) {  		whence = SEEK_SET;  		offset = _start_off + _declared_len + offset;  	} +  	int ret = lseek(_fd, offset, whence); +  	if (ret == -1)  		return false; +  	_pos = ret - _start_off;  	_eos = false; +  	return true;  }  AndroidAssetArchive::AndroidAssetArchive(jobject am) { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	_am = env->NewGlobalRef(am);  	jclass cls = env->GetObjectClass(_am);  	MID_open = env->GetMethodID(cls, "open",  								"(Ljava/lang/String;I)Ljava/io/InputStream;");  	assert(MID_open); +  	MID_openFd = env->GetMethodID(cls, "openFd", -								  "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); +									"(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");  	assert(MID_openFd); +  	MID_list = env->GetMethodID(cls, "list",  								"(Ljava/lang/String;)[Ljava/lang/String;");  	assert(MID_list);  }  AndroidAssetArchive::~AndroidAssetArchive() { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	env->DeleteGlobalRef(_am);  }  bool AndroidAssetArchive::hasFile(const Common::String &name) { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	jstring path = env->NewStringUTF(name.c_str());  	jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN);  	if (env->ExceptionCheck()) { @@ -326,15 +401,18 @@ bool AndroidAssetArchive::hasFile(const Common::String &name) {  		//env->ExceptionDescribe();  		env->ExceptionClear();  		env->DeleteLocalRef(path); +  		return false;  	} +  	env->DeleteLocalRef(result);  	env->DeleteLocalRef(path); +  	return true;  }  int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	Common::List<Common::String> dirlist;  	dirlist.push_back(""); @@ -345,29 +423,36 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) {  		jstring jpath = env->NewStringUTF(dir.c_str());  		jobjectArray jpathlist = static_cast<jobjectArray>(env->CallObjectMethod(_am, MID_list, jpath)); +  		if (env->ExceptionCheck()) {  			warning("Error while calling AssetManager->list(%s). Ignoring.",  					dir.c_str());  			env->ExceptionDescribe();  			env->ExceptionClear(); -			continue;  // May as well keep going ... + +			// May as well keep going ... +			continue;  		} +  		env->DeleteLocalRef(jpath);  		for (jsize i = 0; i < env->GetArrayLength(jpathlist); ++i) {  			jstring elem = (jstring)env->GetObjectArrayElement(jpathlist, i); -			const char* p = env->GetStringUTFChars(elem, NULL); +			const char *p = env->GetStringUTFChars(elem, 0);  			Common::String thispath = dir; +  			if (!thispath.empty())  				thispath += "/"; +  			thispath += p;  			// Assume files have a . in them, and directories don't  			if (strchr(p, '.')) {  				member_list.push_back(getMember(thispath));  				++count; -			} else +			} else {  				dirlist.push_back(thispath); +			}  			env->ReleaseStringUTFChars(elem, p);  			env->DeleteLocalRef(elem); @@ -384,14 +469,15 @@ Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &na  }  Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { -	JNIEnv* env = JNU_GetEnv(); +	JNIEnv *env = JNU_GetEnv();  	jstring jpath = env->NewStringUTF(path.c_str());  	// Try openFd() first ...  	jobject afd = env->CallObjectMethod(_am, MID_openFd, jpath); +  	if (env->ExceptionCheck())  		env->ExceptionClear(); -	else if (afd != NULL) { +	else if (afd != 0) {  		// success :)  		env->DeleteLocalRef(jpath);  		return new AssetFdReadStream(env, afd); @@ -399,13 +485,15 @@ Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const  	// ... and fallback to normal open() if that doesn't work  	jobject is = env->CallObjectMethod(_am, MID_open, jpath, ACCESS_RANDOM); +  	if (env->ExceptionCheck()) {  		// Assume FileNotFoundException  		//warning("Error opening %s", path.c_str());  		//env->ExceptionDescribe();  		env->ExceptionClear();  		env->DeleteLocalRef(jpath); -		return NULL; + +		return 0;  	}  	return new JavaInputStream(env, is); diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp index b9c3f9a1f8..f5ec0b45d9 100644 --- a/backends/platform/android/video.cpp +++ b/backends/platform/android/video.cpp @@ -54,7 +54,7 @@  #if 0  #define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__) -static const char* getGlErrStr(GLenum error) { +static const char *getGlErrStr(GLenum error) {  	switch (error) {  	case GL_NO_ERROR:		   return "GL_NO_ERROR";  	case GL_INVALID_ENUM:	   return "GL_INVALID_ENUM"; @@ -68,7 +68,7 @@ static const char* getGlErrStr(GLenum error) {  	snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error);  	return buf;  } -static void checkGlError(const char* file, int line) { +static void checkGlError(const char *file, int line) {  	GLenum error = glGetError();  	if (error != GL_NO_ERROR)  		warning("%s:%d: GL error: %s", file, line, getGlErrStr(error)); @@ -84,7 +84,7 @@ static bool draw_tex_supported = false;  #endif  static inline GLfixed xdiv(int numerator, int denominator) { -	assert(numerator < (1<<16)); +	assert(numerator < (1 << 16));  	return (numerator << 16) / denominator;  } @@ -93,21 +93,27 @@ static T nextHigher2(T k) {  	if (k == 0)  		return 1;  	--k; -	for (uint i = 1; i < sizeof(T)*CHAR_BIT; i <<= 1) + +	for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)  		k = k | k >> i; +  	return k + 1;  }  void GLESTexture::initGLExtensions() { -	const char* ext_string = -		reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); +	const char *ext_string = +		reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); +  	__android_log_print(ANDROID_LOG_INFO, LOG_TAG, -				"Extensions: %s", ext_string); +						"Extensions: %s", ext_string); +  	Common::StringTokenizer tokenizer(ext_string, " ");  	while (!tokenizer.empty()) {  		Common::String token = tokenizer.nextToken(); +  		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; @@ -121,11 +127,12 @@ GLESTexture::GLESTexture() :  	_all_dirty(true)  {  	glGenTextures(1, &_texture_name); +  	// This all gets reset later in allocBuffer:  	_surface.w = 0;  	_surface.h = 0;  	_surface.pitch = _texture_width; -	_surface.pixels = NULL; +	_surface.pixels = 0;  	_surface.bytesPerPixel = 0;  } @@ -153,8 +160,8 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {  	_surface.h = h;  	_surface.bytesPerPixel = bpp; +	// Already allocated a sufficiently large buffer?  	if (w <= _texture_width && h <= _texture_height) -		// Already allocated a sufficiently large buffer  		return;  	if (npot_supported) { @@ -164,6 +171,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {  		_texture_width = nextHigher2(_surface.w);  		_texture_height = nextHigher2(_surface.h);  	} +  	_surface.pitch = _texture_width * bpp;  	// Allocate room for the texture now, but pixel data gets uploaded @@ -178,14 +186,15 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  	CHECK_GL_ERROR();  	glTexImage2D(GL_TEXTURE_2D, 0, glFormat(), -		     _texture_width, _texture_height, -		     0, glFormat(), glType(), NULL); +					_texture_width, _texture_height, +					0, glFormat(), glType(), 0);  	CHECK_GL_ERROR();  }  void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, -							   const void* buf, int pitch) { +								const void *buf, int pitch) {  	ENTER("updateBuffer(%u, %u, %u, %u, %p, %d)", x, y, w, h, buf, pitch); +  	glBindTexture(GL_TEXTURE_2D, _texture_name);  	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -202,20 +211,22 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,  #if TEXSUBIMAGE_IS_EXPENSIVE  		byte tmpbuf[w * h * bytesPerPixel()]; -		const byte* src = static_cast<const byte*>(buf); -		byte* dst = tmpbuf; +		const byte *src = static_cast<const byte *>(buf); +		byte *dst = tmpbuf;  		GLuint count = h; +  		do {  			memcpy(dst, src, w * bytesPerPixel());  			dst += w * bytesPerPixel();  			src += pitch;  		} while (--count); +  		glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,  						glFormat(), glType(), tmpbuf);  #else  		// This version avoids the intermediate copy at the expense of  		// repeat glTexSubImage2D calls.  On some devices this is worse. -		const byte* src = static_cast<const byte*>(buf); +		const byte *src = static_cast<const byte *>(buf);  		do {  			glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,  							w, 1, glFormat(), glType(), src); @@ -241,9 +252,13 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {  	// Still a work-in-progress - disabled for now.  	if (false && draw_tex_supported && paletteSize() == 0) {  		//glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -		const GLint crop[4] = {0, _surface.h, _surface.w, -_surface.h}; +		const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; +  		glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); -		glColor4ub(0xff, 0xff, 0xff, 0xff);   // Android GLES bug? + +		// Android GLES bug? +		glColor4ub(0xff, 0xff, 0xff, 0xff); +  		glDrawTexiOES(x, y, 0, w, h);  	} else  #endif @@ -256,18 +271,20 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {  			0, tex_height,  			tex_width, tex_height,  		}; +  		glTexCoordPointer(2, GL_FIXED, 0, texcoords);  		const GLshort vertices[] = { -			x,	 y, -			x+w, y, -			x,	 y+h, -			x+w, y+h, +			x, y, +			x + w, y, +			x, y + h, +			x + w, y + h,  		}; +  		glVertexPointer(2, GL_SHORT, 0, vertices);  		assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); -		glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices)/2); +		glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2);  	}  	_all_dirty = false; @@ -276,7 +293,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {  GLESPaletteTexture::GLESPaletteTexture() :  	GLESTexture(), -	_texture(NULL) +	_texture(0)  {  } @@ -291,8 +308,8 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {  	_surface.h = h;  	_surface.bytesPerPixel = bpp; +	// Already allocated a sufficiently large buffer?  	if (w <= _texture_width && h <= _texture_height) -		// Already allocated a sufficiently large buffer  		return;  	if (npot_supported) { @@ -306,12 +323,14 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {  	// Texture gets uploaded later (from drawTexture()) -	byte* new_buffer = new byte[paletteSize() + +	byte *new_buffer = new byte[paletteSize() +  		_texture_width * _texture_height * bytesPerPixel()];  	if (_texture) { -		memcpy(new_buffer, _texture, paletteSize()); // preserve palette +		// preserve palette +		memcpy(new_buffer, _texture, paletteSize());  		delete[] _texture;  	} +  	_texture = new_buffer;  	_surface.pixels = _texture + paletteSize();  } @@ -323,12 +342,13 @@ void GLESPaletteTexture::fillBuffer(byte x) {  }  void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, -									  GLuint w, GLuint h, -									  const void* buf, int pitch) { +										GLuint w, GLuint h, +										const void *buf, int pitch) {  	_all_dirty = true; -	const byte* src = static_cast<const byte*>(buf); -	byte* dst = static_cast<byte*>(_surface.getBasePtr(x, y)); +	const byte * src = static_cast<const byte *>(buf); +	byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y)); +  	do {  		memcpy(dst, src, w * bytesPerPixel());  		dst += _surface.pitch; @@ -339,9 +359,10 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y,  void GLESPaletteTexture::uploadTexture() const {  	const size_t texture_size =  		paletteSize() + _texture_width * _texture_height * bytesPerPixel(); +  	glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), -						   _texture_width, _texture_height, -						   0, texture_size, _texture); +							_texture_width, _texture_height, +							0, texture_size, _texture);  	CHECK_GL_ERROR();  } diff --git a/backends/platform/android/video.h b/backends/platform/android/video.h index 4b73508907..1e00f9bd57 100644 --- a/backends/platform/android/video.h +++ b/backends/platform/android/video.h @@ -38,30 +38,54 @@ public:  	GLESTexture();  	virtual ~GLESTexture(); +  	virtual void reinitGL();  	virtual void allocBuffer(GLuint width, GLuint height); -	const Graphics::Surface* surface_const() const { return &_surface; } -	GLuint width() const { return _surface.w; } -	GLuint height() const { return _surface.h; } -	GLuint texture_name() const { return _texture_name; } -	bool dirty() const { return _all_dirty || !_dirty_rect.isEmpty(); } + +	const Graphics::Surface *surface_const() const { +		return &_surface; +	} + +	GLuint width() const { +		return _surface.w; +	} + +	GLuint height() const { +		return _surface.h; +	} + +	GLuint texture_name() const { +		return _texture_name; +	} + +	bool dirty() const { +		return _all_dirty || !_dirty_rect.isEmpty(); +	} +  	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, -							  const void* buf, int pitch); +								const void *buf, int pitch);  	virtual void fillBuffer(byte x); +  	virtual void drawTexture() {  		drawTexture(0, 0, _surface.w, _surface.h);  	} +  	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);  protected:  	virtual byte bytesPerPixel() const = 0;  	virtual GLenum glFormat() const = 0;  	virtual GLenum glType() const = 0; -	virtual size_t paletteSize() const { return 0; }; + +	virtual size_t paletteSize() const { +		return 0; +	} +  	void setDirty() {  		_all_dirty = true;  		_dirty_rect = Common::Rect();  	} +  	void setDirtyRect(const Common::Rect& r) {  		if (!_all_dirty) {  			if (_dirty_rect.isEmpty()) @@ -70,28 +94,47 @@ protected:  				_dirty_rect.extend(r);  		}  	} +  	GLuint _texture_name;  	Graphics::Surface _surface;  	GLuint _texture_width;  	GLuint _texture_height;  	bool _all_dirty; -	Common::Rect _dirty_rect;  // Covers dirty area + +	// Covers dirty area +	Common::Rect _dirty_rect;  };  // RGBA4444 texture  class GLES4444Texture : public GLESTexture {  protected: -	virtual byte bytesPerPixel() const { return 2; } -	virtual GLenum glFormat() const { return GL_RGBA; } -	virtual GLenum glType() const { return GL_UNSIGNED_SHORT_4_4_4_4; } +	virtual byte bytesPerPixel() const { +		return 2; +	} + +	virtual GLenum glFormat() const { +		return GL_RGBA; +	} + +	virtual GLenum glType() const { +		return GL_UNSIGNED_SHORT_4_4_4_4; +	}  };  // RGB565 texture  class GLES565Texture : public GLESTexture {  protected: -	virtual byte bytesPerPixel() const { return 2; } -	virtual GLenum glFormat() const { return GL_RGB; } -	virtual GLenum glType() const { return GL_UNSIGNED_SHORT_5_6_5; } +	virtual byte bytesPerPixel() const { +		return 2; +	} + +	virtual GLenum glFormat() const { +		return GL_RGB; +	} + +	virtual GLenum glType() const { +		return GL_UNSIGNED_SHORT_5_6_5; +	}  };  // RGB888 256-entry paletted texture @@ -99,42 +142,73 @@ class GLESPaletteTexture : public GLESTexture {  public:  	GLESPaletteTexture();  	virtual ~GLESPaletteTexture(); +  	virtual void allocBuffer(GLuint width, GLuint height);  	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, -							  const void* buf, int pitch); -	Graphics::Surface* surface() { +								const void *buf, int pitch); + +	Graphics::Surface *surface() {  		setDirty();  		return &_surface;  	} -	void* pixels() { + +	void *pixels() {  		setDirty();  		return _surface.pixels;  	} -	const byte* palette_const() const { return _texture; }; -	byte* palette() { + +	const byte *palette_const() const { +		return _texture; +	}; + +	byte *palette() {  		setDirty();  		return _texture;  	}; +  	virtual void drawTexture() {  		drawTexture(0, 0, _surface.w, _surface.h);  	} +  	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);  	virtual void fillBuffer(byte x); +  protected: -	virtual byte bytesPerPixel() const { return 1; } -	virtual GLenum glFormat() const { return GL_RGB; } -	virtual GLenum glType() const { return GL_PALETTE8_RGB8_OES; } -	virtual size_t paletteSize() const { return 256 * 3; }; +	virtual byte bytesPerPixel() const { +		return 1; +	} + +	virtual GLenum glFormat() const { +		return GL_RGB; +	} + +	virtual GLenum glType() const { +		return GL_PALETTE8_RGB8_OES; +	} + +	virtual size_t paletteSize() const { +		return 256 * 3; +	} +  	virtual void uploadTexture() const; -	byte* _texture; + +	byte *_texture;  };  // RGBA8888 256-entry paletted texture  class GLESPaletteATexture : public GLESPaletteTexture {  protected: -	virtual GLenum glFormat() const { return GL_RGBA; } -	virtual GLenum glType() const { return GL_PALETTE8_RGBA8_OES; } -	virtual size_t paletteSize() const { return 256 * 4; }; +	virtual GLenum glFormat() const { +		return GL_RGBA; +	} + +	virtual GLenum glType() const { +		return GL_PALETTE8_RGBA8_OES; +	} + +	virtual size_t paletteSize() const { +		return 256 * 4; +	}  };  #endif | 
