+
+ Matrix.setIdentityM(this.model, 0);
+ Matrix.setIdentityM(this.view, 0);
+ Matrix.setIdentityM(this.proj, 0);
+
+ // Setup camera
+ float xang = 0.5f;
+ float yang = xang * ((float)height / (float)width);
+
+ Matrix.frustumM(this.proj, 0,
+ -1E-6f * xang, // left
+ 1E-6f * xang, // right
+ -1E-6f * yang, // bottom
+ 1E-6f * yang, // top
+ 1E-6f, // near
+ 10f); // far
+
+ Matrix.rotateM(this.view, 0, 10f, 1, 0, 0);
+ Matrix.translateM(this.view, 0, 0, 0, -1.5f);
+ Matrix.rotateM(this.view, 0, -45f, 1, 0, 0);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ boolean up = event.getActionMasked() == MotionEvent.ACTION_UP;
+
+ float x = event.getX() / this.getWidth();
+ float y = 1-(event.getY() / this.getHeight());
+
+ this.ypos = y;
+ if (y < this.ylim) {
+ int num = this.hand.length;
+ this.xpos = x;
+ this.pick = (int)Math.floor((x*num));
+ if (this.pick < 0) this.pick = 0;
+ if (this.pick >= num) this.pick = num-1;
+ }
+ if (y < this.ylim && !this.drag) {
+ Os.debug("Cards: onTouchEvent - starting drag");
+ this.drag = true;
+ }
+ if (this.drag) {
+ Os.debug("Cards: onTouchEvent - move "
+ + x + "," + y);
+ this.requestRender();
+ }
+ if (y >= this.ylim && this.drag && up) {
+ Os.debug("Cards: onTouchEvent - playing card");
+ }
+ if (up) {
+ Os.debug("Cards: onTouchEvent - ending drag");
+ this.drag = false;
+ }
+ return true;
+ }
+
+ /* Private loading methods */
+ private int loadShader(int type, String code)
+ {
+ Os.debug("Cards: loadShader");
+
+ int shader = GLES20.glCreateShader(type);
+ GLES20.glShaderSource(shader, code);
+ GLES20.glCompileShader(shader);
+ return shader;
+ }
+
+ private int loadTexture(String name)
+ {
+ Os.debug("Cards: loadTexture - " + name);
+
+ final int[] tex = new int[1];
+
+ /* Lookup the resource ID */
+ int id = 0;
+ try {
+ id = R.drawable.class.getField(name).getInt(null);
+ } catch(Exception e) {
+ Os.debug("Cards: lookup failed for '" + name + "'", e);
+ return 0;
+ }
+
+ /* Load the bitmap */
+ Bitmap bitmap = BitmapFactory.decodeResource(this.res, id);
+
+ /* Copy into OpenGL */
+ GLES20.glGenTextures(1, tex, 0);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex[0]);
+ GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
+
+ return tex[0];
+ }
+
+ private FloatBuffer loadBuffer(float[] data)
+ {
+ ByteBuffer bytes = ByteBuffer.allocateDirect(data.length * 4);
+ bytes.order(ByteOrder.nativeOrder());
+
+ FloatBuffer buf = bytes.asFloatBuffer();
+ buf.put(data);
+ buf.position(0);
+
+ return buf;
+ }
+
+ /* Private drawing methods */
+ private void drawTable()
+ {
+ /* Setup view */
+ Matrix.setIdentityM(this.model, 0);
+ GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
+
+ /* Draw table */
+ GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.tableBuf);
+ GLES20.glVertexAttribPointer(this.mapHandle, 2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.table);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
+ }
+
+
+ private void drawHand()
+ {
+ /* Draw hand */
+ int num = this.hand.length;
+ for (int i = 0; i < num; i++) {
+ if (this.drag && this.ypos >= this.ylim && i == this.pick)
+ continue;
+
+ Matrix.setIdentityM(this.model, 0);
+
+ Matrix.rotateM(this.model, 0, 45f, 1f, 0f, 0f);
+ Matrix.translateM(this.model, 0, 0f, -0.3f, 1.20f);
+
+ if (this.drag) {
+ float pct = (float)(i+0.5) / num;
+ float err = this.xpos - pct;
+ float y = (float)this.ypos / this.ylim;
+ float lim = Math.min(Math.max(y,0),1);
+ float fcn = 0.1f
+ * (float)Math.exp(-10*num*Math.pow(y*err,2))
+ * (1f-(float)Math.pow(1-lim, 2));
+ Matrix.translateM(this.model, 0, 0, fcn, 0);
+ }
+
+ float left = -20f + 20f*(1f/num);
+ float right = 54f - 54f*(1f/num);
+ float ang = left + i*(right-left)/num;
+ Matrix.rotateM(this.model, 0, ang, 0f, 0f, -1f);
+ Matrix.translateM(this.model, 0, 0f, 0.15f, 0f);
+
+ GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
+ this.drawCard(this.hand[i]);
+ }
+ }
+
+ private void drawPick()
+ {
+ /* Draw selected card */
+ if (this.drag && this.ypos >= this.ylim) {
+ Matrix.setIdentityM(this.model, 0);
+ Matrix.rotateM(this.model, 0, 45f, 1f, 0f, 0f);
+ Matrix.translateM(this.model, 0, 0f, 0f, 1.20f);
+ GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
+ this.drawCard(this.hand[this.pick]);
+ }
+ }
+
+ private void drawCard(String name)
+ {
+ int idx = this.index.get(name);
+ int front = this.face[idx];
+ int back = this.red;
+
+ /* Draw front */
+ GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.faceBuf);
+ GLES20.glVertexAttribPointer(this.mapHandle, 2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, front);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
+
+ /* Draw back */
+ GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.backBuf);
+ GLES20.glVertexAttribPointer(this.mapHandle, 2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, back);
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);