project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/SDLActivity.java
branchhedgeroid
changeset 6047 10011f051f9c
parent 6045 9a7cc0f29430
child 6049 7bc38086d771
equal deleted inserted replaced
6045:9a7cc0f29430 6047:10011f051f9c
     1 package org.hedgewars.mobile;
       
     2 
       
     3 import javax.microedition.khronos.egl.EGL10;
       
     4 import javax.microedition.khronos.egl.EGLConfig;
       
     5 import javax.microedition.khronos.egl.EGLContext;
       
     6 import javax.microedition.khronos.egl.EGLDisplay;
       
     7 import javax.microedition.khronos.egl.EGLSurface;
       
     8 
       
     9 import org.hedgewars.mobile.EngineProtocol.EngineProtocolNetwork;
       
    10 import org.hedgewars.mobile.EngineProtocol.GameConfig;
       
    11 import org.hedgewars.mobile.EngineProtocol.PascalExports;
       
    12 import org.hedgewars.mobile.TouchInterface.TouchInterface;
       
    13 
       
    14 import android.app.Activity;
       
    15 import android.content.Context;
       
    16 import android.graphics.Canvas;
       
    17 import android.graphics.PixelFormat;
       
    18 import android.hardware.Sensor;
       
    19 import android.hardware.SensorEvent;
       
    20 import android.hardware.SensorEventListener;
       
    21 import android.hardware.SensorManager;
       
    22 import android.media.AudioFormat;
       
    23 import android.media.AudioManager;
       
    24 import android.media.AudioTrack;
       
    25 import android.os.Bundle;
       
    26 import android.os.Handler;
       
    27 import android.os.Message;
       
    28 import android.util.Log;
       
    29 import android.view.KeyEvent;
       
    30 import android.view.SurfaceHolder;
       
    31 import android.view.SurfaceView;
       
    32 import android.view.View;
       
    33 
       
    34 /**
       
    35  * SDL Activity
       
    36  */
       
    37 public class SDLActivity extends Activity {
       
    38 
       
    39 	// Main components
       
    40 	public static SDLActivity mSingleton;
       
    41 	public static SDLSurface mSurface;
       
    42 
       
    43 	// Audio
       
    44 	private static Thread mAudioThread;
       
    45 	private static AudioTrack mAudioTrack;
       
    46 
       
    47 	// Load the .so
       
    48 	static {
       
    49 		System.loadLibrary("SDL");
       
    50 		System.loadLibrary("SDL_image");
       
    51 		System.loadLibrary("mikmod");
       
    52 		System.loadLibrary("SDL_net");
       
    53 		System.loadLibrary("SDL_mixer");
       
    54 		System.loadLibrary("SDL_ttf");
       
    55 		System.loadLibrary("lua5.1");
       
    56 		System.loadLibrary("hwengine");
       
    57 		System.loadLibrary("main");
       
    58 	}
       
    59 
       
    60 	// Setup
       
    61 	protected void onCreate(Bundle savedInstanceState) {
       
    62 		// Log.v("SDL", "onCreate()");
       
    63 		super.onCreate(savedInstanceState);
       
    64 
       
    65 		// So we can call stuff from static callbacks
       
    66 		mSingleton = this;
       
    67 
       
    68 		// Set up the surface
       
    69 		GameConfig config = getIntent().getParcelableExtra("config");
       
    70 		mSurface = new SDLSurface(getApplication(), config);
       
    71 		setContentView(mSurface);
       
    72 		SurfaceHolder holder = mSurface.getHolder();
       
    73 		holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
       
    74 	}
       
    75 
       
    76 	// Events
       
    77 	protected void onPause() {
       
    78 		// Log.v("SDL", "onPause()");
       
    79 		super.onPause();
       
    80 
       
    81 	}
       
    82 
       
    83 	protected void onResume() {
       
    84 		// Log.v("SDL", "onResume()");
       
    85 		super.onResume();
       
    86 	}
       
    87 	
       
    88 	public void onBackPressed(){
       
    89 		nativeQuit();
       
    90 		super.onBackPressed();
       
    91 	}
       
    92 
       
    93 	// Messages from the SDLMain thread
       
    94 	static int COMMAND_CHANGE_TITLE = 1;
       
    95 
       
    96 	// Handler for the messages
       
    97 	Handler commandHandler = new Handler() {
       
    98 		public void handleMessage(Message msg) {
       
    99 			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
       
   100 				setTitle((String) msg.obj);
       
   101 			}
       
   102 		}
       
   103 	};
       
   104 
       
   105 	// Send a message from the SDLMain thread
       
   106 	void sendCommand(int command, Object data) {
       
   107 		Message msg = commandHandler.obtainMessage();
       
   108 		msg.arg1 = command;
       
   109 		msg.obj = data;
       
   110 		commandHandler.sendMessage(msg);
       
   111 	}
       
   112 
       
   113 	// C functions we call
       
   114 	public static native void nativeInit(String[] argv);
       
   115 
       
   116 	public static native void nativeQuit();
       
   117 
       
   118 	public static native void onNativeResize(int x, int y, int format);
       
   119 
       
   120 	public static native void onNativeKeyDown(int keycode);
       
   121 
       
   122 	public static native void onNativeKeyUp(int keycode);
       
   123 
       
   124 	public static native void onNativeTouch(int action, int pointer, float x, float y,
       
   125 			float p);
       
   126 
       
   127 	public static native void onNativeAccel(float x, float y, float z);
       
   128 
       
   129 	public static native void nativeRunAudioThread();
       
   130 
       
   131 	// Java functions called from C
       
   132 
       
   133 	public static boolean createGLContext(int majorVersion, int minorVersion) {
       
   134 		return mSurface.initEGL(majorVersion, minorVersion);
       
   135 	}
       
   136 
       
   137 	public static void flipBuffers() {
       
   138 		mSurface.flipEGL();
       
   139 	}
       
   140 
       
   141 	public static void setActivityTitle(String title) {
       
   142 		// Called from SDLMain() thread and can't directly affect the view
       
   143 		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
       
   144 	}
       
   145 
       
   146 	// Audio
       
   147 	private static Object buf;
       
   148 
       
   149 	public static Object audioInit(int sampleRate, boolean is16Bit,
       
   150 			boolean isStereo, int desiredFrames) {
       
   151 		int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO
       
   152 				: AudioFormat.CHANNEL_CONFIGURATION_MONO;
       
   153 		int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT
       
   154 				: AudioFormat.ENCODING_PCM_8BIT;
       
   155 		int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
       
   156 
       
   157 		Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono")
       
   158 				+ " " + (is16Bit ? "16-bit" : "8-bit") + " "
       
   159 				+ ((float) sampleRate / 1000f) + "kHz, " + desiredFrames
       
   160 				+ " frames buffer");
       
   161 
       
   162 		// Let the user pick a larger buffer if they really want -- but ye
       
   163 		// gods they probably shouldn't, the minimums are horrifyingly high
       
   164 		// latency already
       
   165 		desiredFrames = Math.max(
       
   166 				desiredFrames,
       
   167 				(AudioTrack.getMinBufferSize(sampleRate, channelConfig,
       
   168 						audioFormat) + frameSize - 1)
       
   169 						/ frameSize);
       
   170 
       
   171 		mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
       
   172 				channelConfig, audioFormat, desiredFrames * frameSize,
       
   173 				AudioTrack.MODE_STREAM);
       
   174 
       
   175 		audioStartThread();
       
   176 
       
   177 		Log.v("SDL",
       
   178 				"SDL audio: got "
       
   179 						+ ((mAudioTrack.getChannelCount() >= 2) ? "stereo"
       
   180 								: "mono")
       
   181 						+ " "
       
   182 						+ ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit"
       
   183 								: "8-bit") + " "
       
   184 						+ ((float) mAudioTrack.getSampleRate() / 1000f)
       
   185 						+ "kHz, " + desiredFrames + " frames buffer");
       
   186 
       
   187 		if (is16Bit) {
       
   188 			buf = new short[desiredFrames * (isStereo ? 2 : 1)];
       
   189 		} else {
       
   190 			buf = new byte[desiredFrames * (isStereo ? 2 : 1)];
       
   191 		}
       
   192 		return buf;
       
   193 	}
       
   194 
       
   195 	public static void audioStartThread() {
       
   196 		mAudioThread = new Thread(new Runnable() {
       
   197 			public void run() {
       
   198 				mAudioTrack.play();
       
   199 				nativeRunAudioThread();
       
   200 			}
       
   201 		});
       
   202 
       
   203 		// I'd take REALTIME if I could get it!
       
   204 		mAudioThread.setPriority(Thread.MAX_PRIORITY);
       
   205 		mAudioThread.start();
       
   206 	}
       
   207 
       
   208 	public static void audioWriteShortBuffer(short[] buffer) {
       
   209 		for (int i = 0; i < buffer.length;) {
       
   210 			int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   211 			if (result > 0) {
       
   212 				i += result;
       
   213 			} else if (result == 0) {
       
   214 				try {
       
   215 					Thread.sleep(1);
       
   216 				} catch (InterruptedException e) {
       
   217 					// Nom nom
       
   218 				}
       
   219 			} else {
       
   220 				Log.w("SDL", "SDL audio: error return from write(short)");
       
   221 				return;
       
   222 			}
       
   223 		}
       
   224 	}
       
   225 
       
   226 	public static void audioWriteByteBuffer(byte[] buffer) {
       
   227 		for (int i = 0; i < buffer.length;) {
       
   228 			int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   229 			if (result > 0) {
       
   230 				i += result;
       
   231 			} else if (result == 0) {
       
   232 				try {
       
   233 					Thread.sleep(1);
       
   234 				} catch (InterruptedException e) {
       
   235 					// Nom nom
       
   236 				}
       
   237 			} else {
       
   238 				Log.w("SDL", "SDL audio: error return from write(short)");
       
   239 				return;
       
   240 			}
       
   241 		}
       
   242 	}
       
   243 
       
   244 	public static void audioQuit() {
       
   245 		if (mAudioThread != null) {
       
   246 			try {
       
   247 				mAudioThread.join();
       
   248 			} catch (Exception e) {
       
   249 				Log.v("SDL", "Problem stopping audio thread: " + e);
       
   250 			}
       
   251 			mAudioThread = null;
       
   252 
       
   253 			// Log.v("SDL", "Finished waiting for audio thread");
       
   254 		}
       
   255 
       
   256 		if (mAudioTrack != null) {
       
   257 			mAudioTrack.stop();
       
   258 			mAudioTrack = null;
       
   259 		}
       
   260 	}
       
   261 }
       
   262 
       
   263 /**
       
   264  * Simple nativeInit() runnable
       
   265  */
       
   266 class SDLMain implements Runnable {
       
   267 	private int surfaceWidth, surfaceHeight;
       
   268 	private GameConfig config;
       
   269 
       
   270 	public SDLMain(int width, int height, GameConfig _config) {
       
   271 		config = _config;
       
   272 		surfaceWidth = width;
       
   273 		surfaceHeight = height;
       
   274 	}
       
   275 
       
   276 	public void run() {
       
   277 		//Set up the IPC socket server to communicate with the engine
       
   278 		EngineProtocolNetwork ipc = new EngineProtocolNetwork(config);
       
   279 
       
   280 		String path = Utils.getDownloadPath(SDLActivity.mSingleton);//This represents the data directory
       
   281 		path = path.substring(0, path.length()-1);//remove the trailing '/'
       
   282 
       
   283 		
       
   284 		// Runs SDL_main() with added parameters
       
   285 		SDLActivity.nativeInit(new String[] { String.valueOf(ipc.port),
       
   286 				String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
       
   287 				"0", "null", "xeli", "1", "1", "1", path, ""  });
       
   288 
       
   289 		try {
       
   290 			ipc.quitIPC();
       
   291 			ipc.join();
       
   292 		} catch (InterruptedException e) {
       
   293 			e.printStackTrace();
       
   294 		}
       
   295 		//Log.v("SDL", "SDL thread terminated");
       
   296 		SDLActivity.mSingleton.finish();
       
   297 	}
       
   298 }
       
   299 
       
   300 /**
       
   301  * SDLSurface. This is what we draw on, so we need to know when it's created in
       
   302  * order to do anything useful.
       
   303  * 
       
   304  * Because of this, that's where we set up the SDL thread
       
   305  */
       
   306 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
       
   307 		View.OnKeyListener, SensorEventListener {
       
   308 
       
   309 	// This is what SDL runs in. It invokes SDL_main(), eventually
       
   310 	private Thread mSDLThread;
       
   311 
       
   312 	// EGL private objects
       
   313 	private EGLContext mEGLContext;
       
   314 	private EGLSurface mEGLSurface;
       
   315 	private EGLDisplay mEGLDisplay;
       
   316 
       
   317 	// Sensors
       
   318 	private static SensorManager mSensorManager;
       
   319 
       
   320 	private GameConfig config;
       
   321 
       
   322 	// Startup
       
   323 	public SDLSurface(Context context, GameConfig _config) {
       
   324 		super(context);
       
   325 		getHolder().addCallback(this);
       
   326 
       
   327 		setFocusable(true);
       
   328 		setFocusableInTouchMode(true);
       
   329 		requestFocus();
       
   330 		setOnKeyListener(this);
       
   331 		setOnTouchListener(TouchInterface.getTouchInterface());
       
   332 
       
   333 		mSensorManager = (SensorManager) context.getSystemService("sensor");
       
   334 
       
   335 		config = _config;
       
   336 	}
       
   337 
       
   338 	// Called when we have a valid drawing surface
       
   339 	public void surfaceCreated(SurfaceHolder holder) {
       
   340 		Log.v("SDL", "surfaceCreated()");
       
   341 
       
   342 		//enableSensor(Sensor.TYPE_ACCELEROMETER, true);
       
   343 	}
       
   344 
       
   345 	// Called when we lose the surface
       
   346 	public void surfaceDestroyed(SurfaceHolder holder) {
       
   347 		Log.v("SDL", "surfaceDestroyed()");
       
   348 
       
   349 		// Send a quit message to the application
       
   350 		//SDLActivity.nativeQuit();
       
   351                 PascalExports.HWterminate(true);
       
   352 
       
   353 		// Now wait for the SDL thread to quit
       
   354 		if (mSDLThread != null) {
       
   355 			try {
       
   356 				mSDLThread.join();
       
   357 			} catch (Exception e) {
       
   358 				Log.v("SDL", "Problem stopping thread: " + e);
       
   359 			}
       
   360 			mSDLThread = null;
       
   361 
       
   362 			Log.v("SDL", "Finished waiting for SDL thread");
       
   363 		}
       
   364 
       
   365 		//enableSensor(Sensor.TYPE_ACCELEROMETER, false);
       
   366 	}
       
   367 
       
   368 	// Called when the surface is resized
       
   369 	public void surfaceChanged(SurfaceHolder holder, int format, int width,
       
   370 			int height) {
       
   371 		Log.d("SDL", "surfaceChanged()" + width + " + " + height);
       
   372 
       
   373 		int sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565 by default
       
   374 		switch (format) {
       
   375 		case PixelFormat.A_8:
       
   376 			Log.v("SDL", "pixel format A_8");
       
   377 			break;
       
   378 		case PixelFormat.LA_88:
       
   379 			Log.v("SDL", "pixel format LA_88");
       
   380 			break;
       
   381 		case PixelFormat.L_8:
       
   382 			Log.v("SDL", "pixel format L_8");
       
   383 			break;
       
   384 		case PixelFormat.RGBA_4444:
       
   385 			Log.v("SDL", "pixel format RGBA_4444");
       
   386 			sdlFormat = 0x85421002; // SDL_PIXELFORMAT_RGBA4444
       
   387 			break;
       
   388 		case PixelFormat.RGBA_5551:
       
   389 			Log.v("SDL", "pixel format RGBA_5551");
       
   390 			sdlFormat = 0x85441002; // SDL_PIXELFORMAT_RGBA5551
       
   391 			break;
       
   392 		case PixelFormat.RGBA_8888:
       
   393 			Log.v("SDL", "pixel format RGBA_8888");
       
   394 			sdlFormat = 0x86462004; // SDL_PIXELFORMAT_RGBA8888
       
   395 			break;
       
   396 		case PixelFormat.RGBX_8888:
       
   397 			Log.v("SDL", "pixel format RGBX_8888");
       
   398 			sdlFormat = 0x86262004; // SDL_PIXELFORMAT_RGBX8888
       
   399 			break;
       
   400 		case PixelFormat.RGB_332:
       
   401 			Log.v("SDL", "pixel format RGB_332");
       
   402 			sdlFormat = 0x84110801; // SDL_PIXELFORMAT_RGB332
       
   403 			break;
       
   404 		case PixelFormat.RGB_565:
       
   405 			Log.v("SDL", "pixel format RGB_565");
       
   406 			sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565
       
   407 			break;
       
   408 		case PixelFormat.RGB_888:
       
   409 			Log.v("SDL", "pixel format RGB_888");
       
   410 			// Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
       
   411 			sdlFormat = 0x86161804; // SDL_PIXELFORMAT_RGB888
       
   412 			break;
       
   413 		default:
       
   414 			Log.v("SDL", "pixel format unknown " + format);
       
   415 			break;
       
   416 		}
       
   417 		SDLActivity.onNativeResize(width, height, sdlFormat);
       
   418 
       
   419 		// Now start up the C app thread
       
   420 		if (mSDLThread == null) {
       
   421 			mSDLThread = new Thread(new SDLMain(width, height, config),
       
   422 					"SDLThread");
       
   423 			mSDLThread.start();
       
   424 		}
       
   425 	}
       
   426 
       
   427 	// unused
       
   428 	public void onDraw(Canvas canvas) {
       
   429 	}
       
   430 
       
   431 	// EGL functions
       
   432 	public boolean initEGL(int majorVersion, int minorVersion) {
       
   433 		Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "."
       
   434 				+ minorVersion);
       
   435 
       
   436 		try {
       
   437 			EGL10 egl = (EGL10) EGLContext.getEGL();
       
   438 
       
   439 			EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
       
   440 
       
   441 			int[] version = new int[2];
       
   442 			egl.eglInitialize(dpy, version);
       
   443 
       
   444 			int EGL_OPENGL_ES_BIT = 1;
       
   445 			int EGL_OPENGL_ES2_BIT = 4;
       
   446 			int renderableType = 0;
       
   447 			if (majorVersion == 2) {
       
   448 				renderableType = EGL_OPENGL_ES2_BIT;
       
   449 			} else if (majorVersion == 1) {
       
   450 				renderableType = EGL_OPENGL_ES_BIT;
       
   451 			}
       
   452 			int[] configSpec = {
       
   453 					// EGL10.EGL_DEPTH_SIZE, 16,
       
   454 					EGL10.EGL_RENDERABLE_TYPE, renderableType, EGL10.EGL_NONE };
       
   455 			EGLConfig[] configs = new EGLConfig[1];
       
   456 			int[] num_config = new int[1];
       
   457 			if (!egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config)
       
   458 					|| num_config[0] == 0) {
       
   459 				Log.e("SDL", "No EGL config available");
       
   460 				return false;
       
   461 			}
       
   462 			EGLConfig config = configs[0];
       
   463 
       
   464 			EGLContext ctx = egl.eglCreateContext(dpy, config,
       
   465 					EGL10.EGL_NO_CONTEXT, null);
       
   466 			if (ctx == EGL10.EGL_NO_CONTEXT) {
       
   467 				Log.e("SDL", "Couldn't create context");
       
   468 				return false;
       
   469 			}
       
   470 
       
   471 			EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this,
       
   472 					null);
       
   473 			if (surface == EGL10.EGL_NO_SURFACE) {
       
   474 				Log.e("SDL", "Couldn't create surface");
       
   475 				return false;
       
   476 			}
       
   477 
       
   478 			if (!egl.eglMakeCurrent(dpy, surface, surface, ctx)) {
       
   479 				Log.e("SDL", "Couldn't make context current");
       
   480 				return false;
       
   481 			}
       
   482 
       
   483 			mEGLContext = ctx;
       
   484 			mEGLDisplay = dpy;
       
   485 			mEGLSurface = surface;
       
   486 
       
   487 		} catch (Exception e) {
       
   488 			Log.v("SDL", e + "");
       
   489 			for (StackTraceElement s : e.getStackTrace()) {
       
   490 				Log.v("SDL", s.toString());
       
   491 			}
       
   492 		}
       
   493 
       
   494 		return true;
       
   495 	}
       
   496 
       
   497 	// EGL buffer flip
       
   498 	public void flipEGL() {
       
   499 		try {
       
   500 			EGL10 egl = (EGL10) EGLContext.getEGL();
       
   501 
       
   502 			egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null);
       
   503 
       
   504 			// drawing here
       
   505 
       
   506 			egl.eglWaitGL();
       
   507 
       
   508 			egl.eglSwapBuffers(mEGLDisplay, mEGLSurface);
       
   509 
       
   510 		} catch (Exception e) {
       
   511 			Log.v("SDL", "flipEGL(): " + e);
       
   512 			for (StackTraceElement s : e.getStackTrace()) {
       
   513 				Log.v("SDL", s.toString());
       
   514 			}
       
   515 			
       
   516 		}
       
   517 	}
       
   518 
       
   519 	// Key events
       
   520 	public boolean onKey(View v, int keyCode, KeyEvent event) {
       
   521                 if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) return false;
       
   522 		if (event.getAction() == KeyEvent.ACTION_DOWN) {
       
   523 			Log.v("SDL", "key down: " + keyCode);
       
   524 			if(keyCode == KeyEvent.KEYCODE_BACK){//TODO ask user to quit or not
       
   525 				PascalExports.HWterminate(true);
       
   526 				//SDLActivity.mSingleton.finish();
       
   527 			}else{
       
   528 				SDLActivity.onNativeKeyDown(keyCode);	
       
   529 			}
       
   530 			
       
   531 			return true;
       
   532 		} else if (event.getAction() == KeyEvent.ACTION_UP) {
       
   533 			Log.v("SDL", "key up: " + keyCode);
       
   534 			SDLActivity.onNativeKeyUp(keyCode);
       
   535 			return true;
       
   536 		}
       
   537 
       
   538 		return false;
       
   539 	}
       
   540 
       
   541 	// Sensor events
       
   542 	public void enableSensor(int sensortype, boolean enabled) {
       
   543 		// TODO: This uses getDefaultSensor - what if we have >1 accels?
       
   544 		if (enabled) {
       
   545 			mSensorManager.registerListener(this,
       
   546 					mSensorManager.getDefaultSensor(sensortype),
       
   547 					SensorManager.SENSOR_DELAY_GAME, null);
       
   548 		} else {
       
   549 			mSensorManager.unregisterListener(this,
       
   550 					mSensorManager.getDefaultSensor(sensortype));
       
   551 		}
       
   552 	}
       
   553 
       
   554 	public void onAccuracyChanged(Sensor sensor, int accuracy) {
       
   555 		// TODO
       
   556 	}
       
   557 
       
   558 	public void onSensorChanged(SensorEvent event) {
       
   559 		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
       
   560 			SDLActivity.onNativeAccel(event.values[0], event.values[1],
       
   561 					event.values[2]);
       
   562 		}
       
   563 	}
       
   564 
       
   565 }