1 package org.pileus.spades;
4 import java.util.HashMap;
6 import java.nio.ByteBuffer;
7 import java.nio.ByteOrder;
8 import java.nio.FloatBuffer;
10 import javax.microedition.khronos.egl.EGLConfig;
11 import javax.microedition.khronos.opengles.GL10;
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;
22 public class Cards extends GLSurfaceView implements GLSurfaceView.Renderer
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;"
33 + " gl_Position = u_proj"
37 + " v_mapping = a_mapping;"
40 private final String fragSource
41 = "precision mediump float;"
42 + "uniform sampler2D u_texture;"
43 + "uniform vec4 u_color;"
44 + "varying vec2 v_mapping;"
46 + " gl_FragColor = texture2D("
47 + " u_texture, v_mapping);"
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, //
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, //
65 private final float tableCoords[] = {
72 private final float mapCoords[] = {
79 private final float color[] = {
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",
92 private Resources res; // app resources
93 private int program; // opengl program
95 private float[] model; // model matrix
96 private float[] view; // view matrix
97 private float[] proj; // projection matrix
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
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
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
117 private Map<String,Integer> index; // card name to index map
120 public String[] hand; // cards to display
122 /* GLSurfaceView Methods */
123 public Cards(Context context)
126 Os.debug("Cards: create");
128 this.res = context.getResources();
130 this.model = new float[4*4];
131 this.view = new float[4*4];
132 this.proj = new float[4*4];
134 this.face = new int[52];
136 this.hand = new String[] {
137 "As", "7s", "6s", "6h", "2h", "Ac",
138 "Kc", "3c", "10d", "9d", "8d", "7d", "2d"
141 this.index = new HashMap<String,Integer>(52);
142 for (int i = 0; i < 52; i++)
143 this.index.put(this.cards[i], i);
145 this.setEGLContextClientVersion(2);
146 this.setRenderer(this);
147 this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
150 /* Renderer methods */
152 public void onSurfaceCreated(GL10 unused, EGLConfig config)
154 Os.debug("Cards: onSurfaceCreate");
156 /* Initialize shaders */
157 int vertShader = this.loadShader(GLES20.GL_VERTEX_SHADER, vertSource);
158 int fragShader = this.loadShader(GLES20.GL_FRAGMENT_SHADER, fragSource);
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);
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");
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);
182 for (int i = 0; i < 52; i++) {
183 String name = "card_" + this.cards[i].toLowerCase();
184 this.face[i] = this.loadTexture(name);
186 this.red = this.loadTexture("card_red");
187 this.blue = this.loadTexture("card_blue");
188 this.table = this.loadTexture("table");
191 Os.debug("Cards: onSurfaceCreate");
195 public void onDrawFrame(GL10 unused)
197 Os.debug("Cards: onDrawFrame");
199 /* Turn on the program */
200 GLES20.glUseProgram(program);
203 GLES20.glClearColor(0, 0, 0, 1);
204 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
206 /* Setup projection matricies */
207 GLES20.glUniformMatrix4fv(this.viewHandle, 1, false, this.view, 0);
208 GLES20.glUniformMatrix4fv(this.projHandle, 1, false, this.proj, 0);
210 /* Setup buffers objects */
211 GLES20.glEnableVertexAttribArray(this.vertHandle);
212 GLES20.glEnableVertexAttribArray(this.mapHandle);
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);
222 Matrix.setIdentityM(this.model, 0);
223 GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, this.model, 0);
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]);
241 public void onSurfaceChanged(GL10 unused, int width, int height)
243 Os.debug("Cards: onSurfaceChanged");
245 GLES20.glViewport(0, 0, width, height);
247 Matrix.setIdentityM(this.model, 0);
248 Matrix.setIdentityM(this.view, 0);
249 Matrix.setIdentityM(this.proj, 0);
253 float yang = xang * ((float)height / (float)width);
255 Matrix.frustumM(this.proj, 0,
256 -1E-6f * xang, // left
257 1E-6f * xang, // right
258 -1E-6f * yang, // bottom
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);
268 /* Private loading methods */
269 private int loadShader(int type, String code)
271 Os.debug("Cards: loadShader");
273 int shader = GLES20.glCreateShader(type);
274 GLES20.glShaderSource(shader, code);
275 GLES20.glCompileShader(shader);
279 private int loadTexture(String name)
281 Os.debug("Cards: loadTexture - " + name);
283 final int[] tex = new int[1];
285 /* Lookup the resource ID */
288 id = R.drawable.class.getField(name).getInt(null);
289 } catch(Exception e) {
290 Os.debug("Cards: lookup failed for '" + name + "'", e);
294 /* Load the bitmap */
295 Bitmap bitmap = BitmapFactory.decodeResource(this.res, id);
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);
307 private FloatBuffer loadBuffer(float[] data)
309 ByteBuffer bytes = ByteBuffer.allocateDirect(data.length * 4);
310 bytes.order(ByteOrder.nativeOrder());
312 FloatBuffer buf = bytes.asFloatBuffer();
319 /* Private drawing methods */
320 private void drawTable()
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);
329 private void drawCard(String name)
331 int idx = this.index.get(name);
332 int front = this.face[idx];
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);
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);