Browse Source

Fixed Bugs & Joypad in Android
================================

-resolved many graphical glitches with multiple lights in GLES2 render
-fixes and WIP apk expansion
-joystick support for Android by Ariel

Juan Linietsky 11 years ago
parent
commit
e9da61411a

+ 11 - 5
drivers/gles2/rasterizer_gles2.cpp

@@ -4239,9 +4239,10 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD
 			LightInstance *li=light_instance_owner.get( liptr[i] );
 			if (!li || li->last_pass!=scene_pass) //lit by light not in visible scene
 				continue;
-			uint8_t light_type=li->base->type;
-			if (li->base->shadow_enabled)
+			uint8_t light_type=li->base->type|0x40; //penalty to ensure directionals always go first
+			if (li->base->shadow_enabled) {
 				light_type|=0x8;
+			}
 			uint16_t sort_key =li->sort_key;
 
 			RenderList::Element *ec;
@@ -4598,7 +4599,7 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 		material_shader.set_uniform(MaterialShaderGLES2::FOG_COLOR_END,Vector3(col_end.r,col_end.g,col_end.b));
 	}
 
-	material_shader.set_uniform(MaterialShaderGLES2::CONST_LIGHT_MULT,p_no_const_light?0.0:1.0);
+
 	//material_shader.set_uniform(MaterialShaderGLES2::TIME,Math::fmod(last_time,300.0));
 	//if uses TIME - draw_next_frame=true
 
@@ -5668,7 +5669,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 					 case VS::MATERIAL_BLEND_MODE_ADD: {
 
 						glBlendEquation(GL_FUNC_ADD);
-						glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+						glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE);
 
 					 } break;
 					 case VS::MATERIAL_BLEND_MODE_SUB: {
@@ -5833,7 +5834,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		}
 
 		material_shader.set_uniform(MaterialShaderGLES2::NORMAL_MULT, e->mirror?-1.0:1.0);
-
+		material_shader.set_uniform(MaterialShaderGLES2::CONST_LIGHT_MULT,additive?0.0:1.0);
 
 
 		_render(e->geometry, material, skeleton,e->owner,e->instance->transform);
@@ -6097,6 +6098,9 @@ void RasterizerGLES2::_draw_tex_bg() {
 	glDepthMask(GL_TRUE);
 	glEnable(GL_DEPTH_TEST);
 	glDisable(GL_CULL_FACE);
+	glDisable(GL_BLEND);
+	glColorMask(1,1,1,1);
+
 
 	RID texture;
 
@@ -6132,6 +6136,7 @@ void RasterizerGLES2::_draw_tex_bg() {
 
 	copy_shader.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA,true);
 
+
 	copy_shader.bind();
 
 	if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
@@ -6350,6 +6355,7 @@ void RasterizerGLES2::end_scene() {
 	_render_list_forward(&opaque_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting);
 
 	if (draw_tex_background) {
+
 		//most 3D vendors recommend drawing a texture bg or skybox here,
 		//after opaque geometry has been drawn
 		//so the zbuffer can get rid of most pixels

+ 25 - 5
drivers/gles2/shaders/material.glsl

@@ -1060,7 +1060,19 @@ LIGHT_SHADER_CODE
 			light+=specular * light_specular * pow( eye_light, specular_exp );
 		}
 #endif
-		diffuse.rgb = ambient_light *diffuse.rgb + light * attenuation * shadow_attenuation;
+		diffuse.rgb = const_light_mult * ambient_light *diffuse.rgb + light * attenuation * shadow_attenuation;
+
+#ifdef USE_FOG
+
+		diffuse.rgb = mix(diffuse.rgb,fog_interp.rgb,fog_interp.a);
+
+# if defined(LIGHT_TYPE_OMNI) || defined (LIGHT_TYPE_SPOT)
+		diffuse.rgb = mix(mix(vec3(0.0),diffuse.rgb,attenuation),diffuse.rgb,const_light_mult);
+# endif
+
+
+#endif
+
 
 	}
 
@@ -1084,9 +1096,10 @@ LIGHT_SHADER_CODE
 
 #ifdef USE_VERTEX_LIGHTING
 
-	vec3 ambient = ambient_light*diffuse.rgb;
+	vec3 ambient = const_light_mult*ambient_light*diffuse.rgb;
 # if defined(LIGHT_TYPE_OMNI) || defined (LIGHT_TYPE_SPOT)
 	ambient*=diffuse_interp.a; //attenuation affects ambient too
+
 # endif
 
 //	diffuse.rgb=(diffuse.rgb * diffuse_interp.rgb + specular * specular_interp)*shadow_attenuation + ambient;
@@ -1094,6 +1107,16 @@ LIGHT_SHADER_CODE
 	diffuse.rgb=(diffuse.rgb * diffuse_interp.rgb + specular * specular_interp)*shadow_attenuation + ambient;
 	diffuse.rgb+=emission * const_light_mult;
 
+#ifdef USE_FOG
+
+	diffuse.rgb = mix(diffuse.rgb,fog_interp.rgb,fog_interp.a);
+
+# if defined(LIGHT_TYPE_OMNI) || defined (LIGHT_TYPE_SPOT)
+	diffuse.rgb = mix(mix(vec3(0.0),diffuse.rgb,diffuse_interp.a),diffuse.rgb,const_light_mult);
+# endif
+
+#endif
+
 #endif
 
 
@@ -1120,10 +1143,7 @@ LIGHT_SHADER_CODE
 
 #else
 
-#ifdef USE_FOG
 
-	diffuse.rgb = mix(diffuse.rgb,fog_interp.rgb,fog_interp.a);
-#endif
 
 #ifdef USE_GLOW
 

+ 1 - 0
platform/android/java/src/com/android/godot/Godot.java

@@ -498,6 +498,7 @@ public class Godot extends Activity implements SensorEventListener
 
 	@Override public void onBackPressed() {
 
+		System.out.printf("** BACK REQUEST!\n");
 		GodotLib.quit();
 	}
 

+ 2 - 0
platform/android/java/src/com/android/godot/GodotLib.java

@@ -52,6 +52,8 @@ public class GodotLib {
      public static native void touch(int what,int pointer,int howmany, int[] arr);
      public static native void accelerometer(float x, float y, float z);
 	 public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
+	 public static native void joybutton(int p_device, int p_but, boolean p_pressed);
+	 public static native void joyaxis(int p_device, int p_axis, float p_value);
      public static native void focusin();
      public static native void focusout();
      public static native void audio();

+ 233 - 3
platform/android/java/src/com/android/godot/GodotView.java

@@ -35,6 +35,7 @@ import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.content.ContextWrapper;
+import android.view.InputDevice;
 
 import java.io.File;
 import javax.microedition.khronos.egl.EGL10;
@@ -99,22 +100,251 @@ public class GodotView extends GLSurfaceView {
 		return activity.gotTouchEvent(event);
 	};
 
+	public int get_godot_button(int keyCode) {
+
+		int button = 0;
+		switch (keyCode) {
+			case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B
+				button = 0;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_B:
+				button = 1;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y
+				button = 2;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_Y:
+				button = 3;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_L1:
+				button = 4;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_L2:
+				button = 6;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_R1:
+				button = 5;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_R2:
+				button = 7;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_SELECT:
+				button = 10;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_START:
+				button = 11;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_THUMBL:
+				button = 8;
+				break;
+			case KeyEvent.KEYCODE_BUTTON_THUMBR:
+				button = 9;
+				break;
+			case KeyEvent.KEYCODE_DPAD_UP:
+				button = 12;
+				break;
+			case KeyEvent.KEYCODE_DPAD_DOWN:
+				button = 13;
+				break;
+			case KeyEvent.KEYCODE_DPAD_LEFT:
+				button = 14;
+				break;
+			case KeyEvent.KEYCODE_DPAD_RIGHT:
+				button = 15;
+				break;
+
+			default:
+				button = keyCode - KeyEvent.KEYCODE_BUTTON_1;
+				break;
+		};
+
+		return button;
+	};
+
 	@Override public boolean onKeyUp(int keyCode, KeyEvent event) {
-		GodotLib.key(keyCode, event.getUnicodeChar(0), false);
+
+		if (keyCode == KeyEvent.KEYCODE_BACK) {
+			return true;
+		}
+
+		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+			return super.onKeyUp(keyCode, event);
+		};
+
+		int source = event.getSource();
+		if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
+
+			int button = get_godot_button(keyCode);
+			int device = event.getDeviceId();
+
+			GodotLib.joybutton(device, button, false);
+			return true;
+		} else {
+
+			GodotLib.key(keyCode, event.getUnicodeChar(0), false);
+		};
 		return super.onKeyUp(keyCode, event);
 	};
 
 	@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
-		GodotLib.key(keyCode, event.getUnicodeChar(0), true);
+
 		if (keyCode == KeyEvent.KEYCODE_BACK) {
+			GodotLib.quit();
 			// press 'back' button should not terminate program
 			//	normal handle 'back' event in game logic
 			return true;
 		}
+
+		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+			return super.onKeyDown(keyCode, event);
+		};
+
+		int source = event.getSource();
+		//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
+
+		if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
+
+			if (event.getRepeatCount() > 0) // ignore key echo
+				return true;
+			int button = get_godot_button(keyCode);
+			int device = event.getDeviceId();
+			//Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device));
+
+			GodotLib.joybutton(device, button, true);
+			return true;
+
+		} else {
+			GodotLib.key(keyCode, event.getUnicodeChar(0), true);
+		};
 		return super.onKeyDown(keyCode, event);
 	}
 
-	private void init(boolean translucent, int depth, int stencil) {
+	public float axis_value(MotionEvent p_event, InputDevice p_device, int p_axis, int p_pos) {
+
+		final InputDevice.MotionRange range = p_device.getMotionRange(p_axis, p_event.getSource());
+		if (range == null)
+			return 0;
+
+		//Log.e(TAG, String.format("axis ranges %f, %f, %f", range.getRange(), range.getMin(), range.getMax()));
+
+		final float flat = range.getFlat();
+		final float value =
+			p_pos < 0 ? p_event.getAxisValue(p_axis):
+			p_event.getHistoricalAxisValue(p_axis, p_pos);
+
+		final float absval = Math.abs(value);
+		if (absval <= flat) {
+			return 0;
+		};
+
+		final float ret = (value - range.getMin()) / range.getRange() * 2 - 1.0f;
+
+		return ret;
+	};
+
+	float[] last_axis_values = { 0, 0, 0, 0, -1, -1 };
+	boolean[] last_axis_buttons = { false, false, false, false, false, false }; // dpad up down left right, ltrigger, rtrigger
+
+	public void process_axis_state(MotionEvent p_event, int p_pos) {
+
+		int device_id = p_event.getDeviceId();
+		InputDevice device = p_event.getDevice();
+		float val;
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_X, p_pos);
+		if (val != last_axis_values[0]) {
+			last_axis_values[0] = val;
+			//Log.e(TAG, String.format("axis moved! axis %d, value %f", 0, val));
+			GodotLib.joyaxis(device_id, 0, val);
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_Y, p_pos);
+		if (val != last_axis_values[1]) {
+			last_axis_values[1] = val;
+			//Log.e(TAG, String.format("axis moved! axis %d, value %f", 1, val));
+			GodotLib.joyaxis(device_id, 1, val);
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_Z, p_pos);
+		if (val != last_axis_values[2]) {
+			last_axis_values[2] = val;
+			//Log.e(TAG, String.format("axis moved! axis %d, value %f", 2, val));
+			GodotLib.joyaxis(device_id, 2, val);
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_RZ, p_pos);
+		if (val != last_axis_values[3]) {
+			last_axis_values[3] = val;
+			//Log.e(TAG, String.format("axis moved! axis %d, value %f", 3, val));
+			GodotLib.joyaxis(device_id, 3, val);
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_LTRIGGER, p_pos);
+		if (val != last_axis_values[4]) {
+			last_axis_values[4] = val;
+			if ((val != 0) != (last_axis_buttons[4])) {
+				last_axis_buttons[4] = (val != 0);
+				GodotLib.joybutton(device_id, 6, (val != 0));
+			};
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_RTRIGGER, p_pos);
+		if (val != last_axis_values[5]) {
+			last_axis_values[5] = val;
+			if ((val != 0) != (last_axis_buttons[5])) {
+				last_axis_buttons[5] = (val != 0);
+				GodotLib.joybutton(device_id, 7, (val != 0));
+			};
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_HAT_Y, p_pos);
+
+		if (last_axis_buttons[0] != (val > 0)) {
+			last_axis_buttons[0] = val > 0;
+			GodotLib.joybutton(device_id, 12, val > 0);
+		};
+		if (last_axis_buttons[1] != (val < 0)) {
+			last_axis_buttons[1] = val < 0;
+			GodotLib.joybutton(device_id, 13, val > 0);
+		};
+
+		val = axis_value(p_event, device, MotionEvent.AXIS_HAT_X, p_pos);
+		if (last_axis_buttons[2] != (val < 0)) {
+			last_axis_buttons[2] = val < 0;
+			GodotLib.joybutton(device_id, 14, val < 0);
+		};
+		if (last_axis_buttons[3] != (val > 0)) {
+			last_axis_buttons[3] = val > 0;
+			GodotLib.joybutton(device_id, 15, val > 0);
+		};
+	};
+
+	@Override public boolean onGenericMotionEvent(MotionEvent event) {
+
+		if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
+
+			// Process all historical movement samples in the batch
+			final int historySize = event.getHistorySize();
+
+			// Process the movements starting from the
+			// earliest historical position in the batch
+			for (int i = 0; i < historySize; i++) {
+				// Process the event at historical position i
+				process_axis_state(event, i);
+			}
+
+			// Process the current movement sample in the batch (position -1)
+			process_axis_state(event, -1);
+			return true;
+
+
+		};
+
+		return super.onGenericMotionEvent(event);
+	};
+
+
+    private void init(boolean translucent, int depth, int stencil) {
 
 		this.setFocusableInTouchMode(true);
 		/* By default, GLSurfaceView() creates a RGB_565 opaque surface.

+ 45 - 0
platform/android/java_glue.cpp

@@ -581,6 +581,8 @@ static Vector3 accelerometer;
 static HashMap<String,JNISingleton*> jni_singletons;
 static jobject godot_io;
 
+static Vector<int> joy_device_ids;
+
 typedef void (*GFXInitFunc)(void *ud,bool gl2);
 
 static jmethodID _on_video_init=0;
@@ -1279,6 +1281,49 @@ static unsigned int android_get_keysym(unsigned int p_code) {
 	return KEY_UNKNOWN;
 }
 
+static int find_device(int p_device) {
+
+	for (int i=0; i<joy_device_ids.size(); i++) {
+
+		if (joy_device_ids[i] == p_device) {
+			//print_line("found device at "+String::num(i));
+			return i;
+		};
+	};
+
+	//print_line("adding a device at" + String::num(joy_device_ids.size()));
+	joy_device_ids.push_back(p_device);
+
+	return joy_device_ids.size() - 1;
+};
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed) {
+
+	InputEvent ievent;
+	ievent.type = InputEvent::JOYSTICK_BUTTON;
+	ievent.device = find_device(p_device);
+	ievent.joy_button.button_index = p_button;
+	ievent.joy_button.pressed = p_pressed;
+
+	input_mutex->lock();
+	key_events.push_back(ievent);
+	input_mutex->unlock();
+};
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
+
+	InputEvent ievent;
+	ievent.type = InputEvent::JOYSTICK_MOTION;
+	ievent.device = find_device(p_device);
+	ievent.joy_motion.axis = p_axis;
+	ievent.joy_motion.axis_value = p_value;
+
+	input_mutex->lock();
+	key_events.push_back(ievent);
+	input_mutex->unlock();
+};
+
+
 JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
 
 	InputEvent ievent;

+ 2 - 0
platform/android/java_glue.h

@@ -43,6 +43,8 @@ extern "C" {
     JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj);
     JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
 	JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
+	JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed);
+	JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value);
 	JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj);
     JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj,  jfloat x, jfloat y, jfloat z);
     JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj);

+ 40 - 1
platform/iphone/app_delegate.mm

@@ -37,6 +37,12 @@
 #include "modules/FacebookScorer_ios/FacebookScorer.h"
 #endif
 
+#ifdef MODULE_GAME_ANALYTICS_ENABLED
+#import "modules/game_analytics/ios/MobileAppTracker.framework/Headers/MobileAppTracker.h"
+//#import "modules/game_analytics/ios/MobileAppTracker.h"
+#import <AdSupport/AdSupport.h>
+#endif
+
 #define kFilteringFactor                        0.1
 #define kRenderingFrequency						60
 #define kAccelerometerFrequency         100.0 // Hz
@@ -210,7 +216,36 @@ static int frame_count = 0;
 	//OSIPhone::screen_width = rect.size.width - rect.origin.x;
 	//OSIPhone::screen_height = rect.size.height - rect.origin.y;
 	
-	mainViewController = view_controller;	
+	mainViewController = view_controller;
+    
+#ifdef MODULE_GAME_ANALYTICS_ENABLED
+    printf("********************* didFinishLaunchingWithOptions\n");
+    if(!Globals::get_singleton()->has("mobileapptracker/advertiser_id"))
+    {
+        return;
+    }
+    if(!Globals::get_singleton()->has("mobileapptracker/conversion_key"))
+    {
+        return;
+    }
+        
+    String adid = GLOBAL_DEF("mobileapptracker/advertiser_id","");
+    String convkey = GLOBAL_DEF("mobileapptracker/conversion_key","");
+        
+    NSString * advertiser_id = [NSString stringWithUTF8String:adid.utf8().get_data()];
+    NSString * conversion_key = [NSString stringWithUTF8String:convkey.utf8().get_data()];
+        
+    // Account Configuration info - must be set
+    [MobileAppTracker initializeWithMATAdvertiserId:advertiser_id
+                                    MATConversionKey:conversion_key];
+        
+    // Used to pass us the IFA, enables highly accurate 1-to-1 attribution.
+    // Required for many advertising networks.
+    [MobileAppTracker setAppleAdvertisingIdentifier:[[ASIdentifierManager sharedManager] advertisingIdentifier]
+        advertisingTrackingEnabled:[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]];
+        
+#endif
+    
 };
 
 - (void)applicationWillTerminate:(UIApplication*)application {
@@ -240,6 +275,10 @@ static int frame_count = 0;
 - (void) applicationDidBecomeActive:(UIApplication *)application
 {
 	printf("********************* did become active\n");
+#ifdef MODULE_GAME_ANALYTICS_ENABLED
+    printf("********************* mobile app tracker found\n");
+	[MobileAppTracker measureSession];
+#endif
 	[view_controller.view startAnimation]; // FIXME: resume seems to be recommended elsewhere
 }