]> Pileus Git - ~andy/spades/blobdiff - src/org/pileus/spades/Cards.java
Fix null pointers and pile parsing
[~andy/spades] / src / org / pileus / spades / Cards.java
index 4149b9d721428152a155a7324673794aaf715060..8703c87a4b0b67df59359b3176abd6171195a4e3 100644 (file)
@@ -1,5 +1,8 @@
 package org.pileus.spades;
 
+import java.util.Map;
+import java.util.HashMap;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
@@ -15,6 +18,7 @@ import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
 import android.opengl.GLUtils;
 import android.opengl.Matrix;
+import android.view.MotionEvent;
 
 public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
 {
@@ -28,8 +32,8 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
                + "varying   vec2 v_mapping;"
                + "void main() {"
                + "  gl_Position = u_proj"
-               + "              * u_model"
                + "              * u_view"
+               + "              * u_model"
                + "              * a_position;"
                + "  v_mapping   = a_mapping;"
                + "}";
@@ -45,11 +49,25 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
                + "}";
 
        /* Drawing data */
-       private final float  vertCoords[] = {
-               -0.063f,  0.088f, 0f, // Standard poker size:
-               -0.063f, -0.088f, 0f, //   2.5in x 3.5in
-                0.063f, -0.088f, 0f, //   63mm  x 88mm
-                0.063f,  0.088f, 0f, //
+       private final float  faceCoords[] = {
+               -0.063f,  0.088f, 0.05f, // Standard poker size:
+               -0.063f, -0.088f, 0.05f, //   2.5in x 3.5in
+                0.063f, -0.088f, 0.05f, //   63mm  x 88mm
+                0.063f,  0.088f, 0.05f, //
+       };
+
+       private final float  backCoords[] = {
+                0.063f,  0.088f, 0.05f, // Standard poker size:
+                0.063f, -0.088f, 0.05f, //   2.5in x 3.5in
+               -0.063f, -0.088f, 0.05f, //   63mm  x 88mm
+               -0.063f,  0.088f, 0.05f, //
+       };
+
+       private final float  tableCoords[] = {
+               -0.75f,  0.75f, 0,
+               -0.75f, -0.75f, 0,
+                0.75f, -0.75f, 0,
+                0.75f,  0.75f, 0,
        };
 
        private final float  mapCoords[] = {
@@ -75,11 +93,13 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
        private Resources    res;         // app resources
        private int          program;     // opengl program
 
-       private float        model[];     // model matrix
-       private float        view[];      // view matrix
-       private float        proj[];      // projection matrix
+       private float[]      model;       // model matrix
+       private float[]      view;        // view matrix
+       private float[]      proj;        // projection matrix
 
-       private FloatBuffer  vertBuf;     // vertex position buffer
+       private FloatBuffer  faceBuf;     // vertex positions for front of card
+       private FloatBuffer  backBuf;     // vertex positions for back of card
+       private FloatBuffer  tableBuf;    // vertex positions for table
        private FloatBuffer  mapBuf;      // texture mapping coord buffer
 
        private int          modelHandle; // model matrix
@@ -90,60 +110,23 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
        private int          texHandle;   // texture data
        private int          colorHandle; // color data
 
-       private int          face[];      // card face textures
+       private int[]        face;        // card face textures
        private int          red;         // red card back
        private int          blue;        // blue card back
+       private int          table;       // table top texture
 
-       /* Private 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 boolean      drag;        // currently in drag event
+       private int          pick;        // currently picked card
+       private float        xpos;        // x drag position (0=left   - 1-right)
+       private float        ypos;        // y drag position (0=bottom - 1-top)
+       private float        ylim;        // y limit for a play
 
-       private FloatBuffer loadBuffer(float[] data)
-       {
-               ByteBuffer bytes = ByteBuffer.allocateDirect(data.length * 4);
-               bytes.order(ByteOrder.nativeOrder());
+       private Map<String,Integer> index; // card name to index map
 
-               FloatBuffer buf = bytes.asFloatBuffer();
-               buf.put(data);
-               buf.position(0);
-
-               return buf;
-       }
+       /* Properties */
+       public Spades        game;        // the spades game
+       public String[]      hand;        // cards to display
+       public String[]      pile;        // played cards to display
 
        /* GLSurfaceView Methods */
        public Cards(Context context)
@@ -151,7 +134,7 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
                super(context);
                Os.debug("Cards: create");
 
-               this.res = context.getResources();
+               this.res   = context.getResources();
 
                this.model = new float[4*4];
                this.view  = new float[4*4];
@@ -159,6 +142,15 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
 
                this.face  = new int[52];
 
+               this.ylim  = 0.4f;
+
+               this.hand  = "As Ks Qs Js 10s 9s 8s 7s 6s 5s 4s 3s 2s".split(" ");
+               this.pile  = "Ah Ac Ad".split(" ");
+
+               this.index = new HashMap<String,Integer>(52);
+               for (int i = 0; i < 52; i++)
+                       this.index.put(this.cards[i], i);
+
                this.setEGLContextClientVersion(2);
                this.setRenderer(this);
                this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
@@ -190,16 +182,19 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
                this.colorHandle = GLES20.glGetUniformLocation(program, "u_color");
 
                /* Create vertex array  */
-               this.vertBuf = this.loadBuffer(this.vertCoords);
-               this.mapBuf  = this.loadBuffer(this.mapCoords);
+               this.faceBuf  = this.loadBuffer(this.faceCoords);
+               this.backBuf  = this.loadBuffer(this.backCoords);
+               this.tableBuf = this.loadBuffer(this.tableCoords);
+               this.mapBuf   = this.loadBuffer(this.mapCoords);
 
                /* Load textures */
                for (int i = 0; i < 52; i++) {
                        String name = "card_" + this.cards[i].toLowerCase();
                        this.face[i] = this.loadTexture(name);
                }
-               this.red  = this.loadTexture("card_red");
-               this.blue = this.loadTexture("card_blue");
+               this.red   = this.loadTexture("card_red");
+               this.blue  = this.loadTexture("card_blue");
+               this.table = this.loadTexture("table");
 
                /* Debug */
                Os.debug("Cards: onSurfaceCreate");
@@ -208,32 +203,35 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
        @Override
        public void onDrawFrame(GL10 unused)
        {
-               Os.debug("Cards: onDrawFrame");
+               //Os.debug("Cards: onDrawFrame");
 
                /* Turn on the program */
                GLES20.glUseProgram(program);
 
-               /* Draw */
+               /* Reset view */
                GLES20.glClearColor(0, 0, 0, 1);
                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
 
-               GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
+               /* Setup projection matricies */
                GLES20.glUniformMatrix4fv(this.viewHandle, 1, false, this.view, 0);
                GLES20.glUniformMatrix4fv(this.projHandle, 1, false, this.proj, 0);
 
+               /* Setup buffers objects */
                GLES20.glEnableVertexAttribArray(this.vertHandle);
                GLES20.glEnableVertexAttribArray(this.mapHandle);
-               GLES20.glVertexAttribPointer(this.vertHandle,  3, GLES20.GL_FLOAT, false, 3*4, this.vertBuf);
-               GLES20.glVertexAttribPointer(this.mapHandle, 2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
 
+               /* Setup texturing */
+               GLES20.glEnable(GLES20.GL_CULL_FACE);
+               GLES20.glEnable(GLES20.GL_BLEND);
+               GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
                GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-               GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.red);
                GLES20.glUniform1i(this.texHandle, 0);
 
-               GLES20.glUniform4fv(this.colorHandle, 1, this.color, 0);
-
-               GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
-               GLES20.glDisableVertexAttribArray(this.mapHandle);
+               /* Draw objects */
+               this.drawTable();
+               this.drawPile();
+               this.drawHand();
+               this.drawPick();
        }
 
        @Override
@@ -259,15 +257,197 @@ public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
                                1E-6f,         // near
                                10f);          // far
 
-               Matrix.translateM(this.view, 0,
-                               0, 0, -2.0f);
-               Matrix.rotateM(this.view, 0,
-                               90f, 1, 0, 0);
+               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");
+                       this.game.onPlay(this.hand[this.pick]);
+               }
+               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());
 
-               // Set card position
-               Matrix.rotateM(this.view, 0,
-                               -90f, 1, 0, 0);
-               Matrix.translateM(this.model, 0,
-                               0, 0, 1.5f);
+               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 drawPile()
+       {
+               /* Draw played cards */
+               for (int i = 0; i < 4; i++) {
+                       if (i >= this.pile.length || this.pile[i] == null)
+                               continue;
+
+                       float ang = i * 90f;
+
+                       Matrix.setIdentityM(this.model, 0);
+
+                       Matrix.rotateM(this.model, 0, -ang, 0f, 0f, 1f);
+                       Matrix.translateM(this.model, 0, -0.30f, 0f, 0f);
+                       Matrix.rotateM(this.model, 0,  ang, 0f, 0f, 1f);
+                       Matrix.scaleM(this.model, 0, 3f, 3f, 0f);
+
+                       this.drawCard(this.pile[i]);
+               }
+       }
+
+       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);
+
+                       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);
+                       this.drawCard(this.hand[this.pick]);
+               }
+       }
+
+       private void drawCard(String name)
+       {
+               if (!this.index.containsKey(name))
+                       return;
+               int idx   = this.index.get(name);
+               int front = this.face[idx];
+               int back  = this.red;
+
+               /* Set model matrix */
+               GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
+
+               /* 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);
        }
 }