]> Pileus Git - ~andy/spades/blob - src/org/pileus/spades/Cards.java
Draw more cards and a table
[~andy/spades] / src / org / pileus / spades / Cards.java
1 package org.pileus.spades;
2
3 import java.util.Map;
4 import java.util.HashMap;
5
6 import java.nio.ByteBuffer;
7 import java.nio.ByteOrder;
8 import java.nio.FloatBuffer;
9
10 import javax.microedition.khronos.egl.EGLConfig;
11 import javax.microedition.khronos.opengles.GL10;
12
13 import android.content.Context;
14 import android.content.res.Resources;
15 import android.graphics.Bitmap;
16 import android.graphics.BitmapFactory;
17 import android.opengl.GLES20;
18 import android.opengl.GLSurfaceView;
19 import android.opengl.GLUtils;
20 import android.opengl.Matrix;
21
22 public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
23 {
24         /* Shader data */
25         private final String vertSource
26                 = "uniform   mat4 u_model;"
27                 + "uniform   mat4 u_view;"
28                 + "uniform   mat4 u_proj;"
29                 + "attribute vec4 a_position;"
30                 + "attribute vec2 a_mapping;"
31                 + "varying   vec2 v_mapping;"
32                 + "void main() {"
33                 + "  gl_Position = u_proj"
34                 + "              * u_view"
35                 + "              * u_model"
36                 + "              * a_position;"
37                 + "  v_mapping   = a_mapping;"
38                 + "}";
39
40         private final String fragSource
41                 = "precision mediump   float;"
42                 + "uniform   sampler2D u_texture;"
43                 + "uniform   vec4      u_color;"
44                 + "varying   vec2      v_mapping;"
45                 + "void main() {"
46                 + "  gl_FragColor = texture2D("
47                 + "    u_texture, v_mapping);"
48                 + "}";
49
50         /* Drawing data */
51         private final float  faceCoords[] = {
52                 -0.063f,  0.088f, 0.05f, // Standard poker size:
53                 -0.063f, -0.088f, 0.05f, //   2.5in x 3.5in
54                  0.063f, -0.088f, 0.05f, //   63mm  x 88mm
55                  0.063f,  0.088f, 0.05f, //
56         };
57
58         private final float  backCoords[] = {
59                  0.063f,  0.088f, 0.05f, // Standard poker size:
60                  0.063f, -0.088f, 0.05f, //   2.5in x 3.5in
61                 -0.063f, -0.088f, 0.05f, //   63mm  x 88mm
62                 -0.063f,  0.088f, 0.05f, //
63         };
64
65         private final float  tableCoords[] = {
66                 -0.75f,  0.75f, 0,
67                 -0.75f, -0.75f, 0,
68                  0.75f, -0.75f, 0,
69                  0.75f,  0.75f, 0,
70         };
71
72         private final float  mapCoords[] = {
73                 0.0f, 0.0f,
74                 0.0f, 1.0f,
75                 1.0f, 1.0f,
76                 1.0f, 0.0f,
77         };
78
79         private final float  color[] = {
80                 1, 0, 0, 1
81         };
82
83         /* Cards data */
84         private final String cards[] = {
85                 "As", "Ks", "Qs", "Js", "10s", "9s", "8s", "7s", "6s", "5s", "4s", "3s", "2s",
86                 "Ah", "Kh", "Qh", "Jh", "10h", "9h", "8h", "7h", "6h", "5h", "4h", "3h", "2h",
87                 "Ac", "Kc", "Qc", "Jc", "10c", "9c", "8c", "7c", "6c", "5c", "4c", "3c", "2c",
88                 "Ad", "Kd", "Qd", "Jd", "10d", "9d", "8d", "7d", "6d", "5d", "4d", "3d", "2d",
89         };
90
91         /* Private data */
92         private Resources    res;         // app resources
93         private int          program;     // opengl program
94
95         private float[]      model;       // model matrix
96         private float[]      view;        // view matrix
97         private float[]      proj;        // projection matrix
98
99         private FloatBuffer  faceBuf;     // vertex positions for front of card
100         private FloatBuffer  backBuf;     // vertex positions for back of card
101         private FloatBuffer  tableBuf;    // vertex positions for table
102         private FloatBuffer  mapBuf;      // texture mapping coord buffer
103
104         private int          modelHandle; // model matrix
105         private int          viewHandle;  // view matrix
106         private int          projHandle;  // projection matrix
107         private int          vertHandle;  // vertex positions
108         private int          mapHandle;   // texture mapping coords
109         private int          texHandle;   // texture data
110         private int          colorHandle; // color data
111
112         private int[]        face;        // card face textures
113         private int          red;         // red card back
114         private int          blue;        // blue card back
115         private int          table;       // table top texture
116
117         private Map<String,Integer> index;    // card name to index map
118
119         /* Properties */
120         public String[]      hand;        // cards to display
121
122         /* GLSurfaceView Methods */
123         public Cards(Context context)
124         {
125                 super(context);
126                 Os.debug("Cards: create");
127
128                 this.res = context.getResources();
129
130                 this.model = new float[4*4];
131                 this.view  = new float[4*4];
132                 this.proj  = new float[4*4];
133
134                 this.face  = new int[52];
135
136                 this.hand  = new String[] {
137                         "As", "7s", "6s",  "6h", "2h", "Ac",
138                         "Kc", "3c", "10d", "9d", "8d", "7d", "2d"
139                 };
140
141                 this.index = new HashMap<String,Integer>(52);
142                 for (int i = 0; i < 52; i++)
143                         this.index.put(this.cards[i], i);
144
145                 this.setEGLContextClientVersion(2);
146                 this.setRenderer(this);
147                 this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
148         }
149
150         /* Renderer methods */
151         @Override
152         public void onSurfaceCreated(GL10 unused, EGLConfig config)
153         {
154                 Os.debug("Cards: onSurfaceCreate");
155
156                 /* Initialize shaders */
157                 int vertShader = this.loadShader(GLES20.GL_VERTEX_SHADER,   vertSource);
158                 int fragShader = this.loadShader(GLES20.GL_FRAGMENT_SHADER, fragSource);
159
160                 /* Link shaders into an OpenGL program */
161                 this.program = GLES20.glCreateProgram();
162                 GLES20.glAttachShader(program, vertShader);
163                 GLES20.glAttachShader(program, fragShader);
164                 GLES20.glLinkProgram(program);
165
166                 /* Get shaders attributes */
167                 this.modelHandle = GLES20.glGetUniformLocation(program, "u_model");
168                 this.viewHandle  = GLES20.glGetUniformLocation(program, "u_view");
169                 this.projHandle  = GLES20.glGetUniformLocation(program, "u_proj");
170                 this.vertHandle  = GLES20.glGetAttribLocation(program, "a_position");
171                 this.mapHandle   = GLES20.glGetAttribLocation(program, "a_mapping");
172                 this.texHandle   = GLES20.glGetUniformLocation(program, "u_texture");
173                 this.colorHandle = GLES20.glGetUniformLocation(program, "u_color");
174
175                 /* Create vertex array  */
176                 this.faceBuf  = this.loadBuffer(this.faceCoords);
177                 this.backBuf  = this.loadBuffer(this.backCoords);
178                 this.tableBuf = this.loadBuffer(this.tableCoords);
179                 this.mapBuf   = this.loadBuffer(this.mapCoords);
180
181                 /* Load textures */
182                 for (int i = 0; i < 52; i++) {
183                         String name = "card_" + this.cards[i].toLowerCase();
184                         this.face[i] = this.loadTexture(name);
185                 }
186                 this.red   = this.loadTexture("card_red");
187                 this.blue  = this.loadTexture("card_blue");
188                 this.table = this.loadTexture("table");
189
190                 /* Debug */
191                 Os.debug("Cards: onSurfaceCreate");
192         }
193
194         @Override
195         public void onDrawFrame(GL10 unused)
196         {
197                 Os.debug("Cards: onDrawFrame");
198
199                 /* Turn on the program */
200                 GLES20.glUseProgram(program);
201
202                 /* Reset view */
203                 GLES20.glClearColor(0, 0, 0, 1);
204                 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
205
206                 /* Setup projection matricies */
207                 GLES20.glUniformMatrix4fv(this.viewHandle, 1, false, this.view, 0);
208                 GLES20.glUniformMatrix4fv(this.projHandle, 1, false, this.proj, 0);
209
210                 /* Setup buffers objects */
211                 GLES20.glEnableVertexAttribArray(this.vertHandle);
212                 GLES20.glEnableVertexAttribArray(this.mapHandle);
213
214                 /* Setup texturing */
215                 GLES20.glEnable(GLES20.GL_CULL_FACE);
216                 GLES20.glEnable(GLES20.GL_BLEND);
217                 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
218                 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
219                 GLES20.glUniform1i(this.texHandle, 0);
220
221                 /* Draw "Table" */
222                 Matrix.setIdentityM(this.model, 0);
223                 GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
224                 this.drawTable();
225
226                 /* Draw cards */
227                 int num = this.hand.length;
228                 for (int i = 0; i < num; i++) {
229                         float ang = 5f * (i + (float)num/5 - (float)num/2f);
230                         Matrix.setIdentityM(this.model, 0);
231                         Matrix.rotateM(this.model, 0, 45f, 1f, 0f, 0f);
232                         Matrix.translateM(this.model, 0, 0f, -0.3f, 1.20f);
233                         Matrix.rotateM(this.model, 0, ang, 0f, 0f, -1f);
234                         Matrix.translateM(this.model, 0, 0f, 0.15f, 0f);
235                         GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
236                         this.drawCard(this.hand[i]);
237                 }
238         }
239
240         @Override
241         public void onSurfaceChanged(GL10 unused, int width, int height)
242         {
243                 Os.debug("Cards: onSurfaceChanged");
244
245                 GLES20.glViewport(0, 0, width, height);
246
247                 Matrix.setIdentityM(this.model, 0);
248                 Matrix.setIdentityM(this.view, 0);
249                 Matrix.setIdentityM(this.proj, 0);
250
251                 // Setup camera
252                 float xang = 0.5f;
253                 float yang = xang * ((float)height / (float)width);
254
255                 Matrix.frustumM(this.proj, 0,
256                                 -1E-6f * xang, // left
257                                 1E-6f  * xang, // right
258                                 -1E-6f * yang, // bottom
259                                 1E-6f  * yang, // top
260                                 1E-6f,         // near
261                                 10f);          // far
262
263                 Matrix.rotateM(this.view, 0, 10f, 1, 0, 0);
264                 Matrix.translateM(this.view, 0, 0, 0, -1.5f);
265                 Matrix.rotateM(this.view, 0, -45f, 1, 0, 0);
266         }
267
268         /* Private loading methods */
269         private int loadShader(int type, String code)
270         {
271                 Os.debug("Cards: loadShader");
272
273                 int shader = GLES20.glCreateShader(type);
274                 GLES20.glShaderSource(shader, code);
275                 GLES20.glCompileShader(shader);
276                 return shader;
277         }
278
279         private int loadTexture(String name)
280         {
281                 Os.debug("Cards: loadTexture - " + name);
282
283                 final int[] tex = new int[1];
284
285                 /* Lookup the resource ID */
286                 int id = 0;
287                 try {
288                         id = R.drawable.class.getField(name).getInt(null);
289                 } catch(Exception e) {
290                         Os.debug("Cards: lookup failed for '" + name + "'", e);
291                         return 0;
292                 }
293
294                 /* Load the bitmap */
295                 Bitmap bitmap = BitmapFactory.decodeResource(this.res, id);
296
297                 /* Copy into OpenGL */
298                 GLES20.glGenTextures(1, tex, 0);
299                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex[0]);
300                 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
301                 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
302                 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
303
304                 return tex[0];
305         }
306
307         private FloatBuffer loadBuffer(float[] data)
308         {
309                 ByteBuffer bytes = ByteBuffer.allocateDirect(data.length * 4);
310                 bytes.order(ByteOrder.nativeOrder());
311
312                 FloatBuffer buf = bytes.asFloatBuffer();
313                 buf.put(data);
314                 buf.position(0);
315
316                 return buf;
317         }
318
319         /* Private drawing methods */
320         private void drawTable()
321         {
322                 /* Draw table */
323                 GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.tableBuf);
324                 GLES20.glVertexAttribPointer(this.mapHandle,  2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
325                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.table);
326                 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
327         }
328
329         private void drawCard(String name)
330         {
331                 int idx   = this.index.get(name);
332                 int front = this.face[idx];
333                 int back  = this.red;
334
335                 /* Draw front */
336                 GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.faceBuf);
337                 GLES20.glVertexAttribPointer(this.mapHandle,  2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
338                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, front);
339                 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
340
341                 /* Draw back */
342                 GLES20.glVertexAttribPointer(this.vertHandle, 3, GLES20.GL_FLOAT, false, 3*4, this.backBuf);
343                 GLES20.glVertexAttribPointer(this.mapHandle,  2, GLES20.GL_FLOAT, false, 2*4, this.mapBuf);
344                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, back);
345                 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
346         }
347 }