Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

/*
 * PROJECT: NyARToolkit on Android
 * --------------------------------------------------------------------------------
 * This work is based on the NyARToolKit developed by
 *   R.Iizuka
 * http://www.hitl.washington.edu/artoolkit/
 *
 * The NyARToolkit on Android is an Application of NyARToolkit
 * to Google Android Emulator Environment.
 * Copyright (C)2008 Shinobu Izumi
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this framework; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For further information please contact.
 *      <stagesp1(at)gmail.com>
 *
 */


package com.tomgibara.android.camera;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

import jp.nyatla.nyartoolkit.NyARException;
import jp.nyatla.nyartoolkit.core.NyARCode;
import jp.nyatla.nyartoolkit.core.raster.NyARRaster_RGB;
import jp.nyatla.nyartoolkit.jogl.utils.GLNyARParam;
import jp.nyatla.nyartoolkit.jogl.utils.GLNyARSingleDetectMarker;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.OpenGLContext;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.SurfaceHolder;

/**
 * A CameraSource implementation that obtains its bitmaps via a TCP connection
 * to a remote host on a specified address/port.
 *
 * Originally written by Tom Gibara
 * http://www.tomgibara.com/android/camera-source
 *
 * Modified for detecting ARMarker and drawing 3D cube.
 *
 * @author Shiva
 *
 */


public class SocketCamera implements CameraSource {

        private static final int SOCKET_TIMEOUT = 5000;

        private final String address;
        private final int port;
        private final Rect bounds;
        private final boolean preserveAspectRatio;
        private final Paint paint = new Paint();
        private final Paint paintBlue = new Paint();

        private GLNyARSingleDetectMarker nya;
        private NyARRaster_RGB raster;
        private GLNyARParam ar_param;
        // private NyARCode ar_code;

        private SurfaceHolder mHolder;

        private final Bitmap fixedBitmap;
        private final Cube mCube = new Cube();

        private int w = -1;
        private int h = -1;
        private int[] pixels;
        private byte[] buf;
        private float[] resultf;

        private static final boolean LOCAL = false;
        private static final boolean TEXT = false;
        private static final boolean DETECT = true;

        public SocketCamera(String address, int port, int width, int height,
                        boolean preserveAspectRatio, GLNyARParam ar_param,
                        NyARCode ar_code, SurfaceHolder holder, Bitmap fixedBitmap) {
                this.address = address;
                this.port = port;
                bounds = new Rect(0, 0, width, height);
                this.preserveAspectRatio = preserveAspectRatio;

                paint.setColor(0xFFFF0000);
                paint.setFilterBitmap(true);
                paint.setAntiAlias(true);

                paintBlue.setColor(0xFF0000FF);
                paintBlue.setFilterBitmap(true);
                paintBlue.setAntiAlias(true);

                this.ar_param = ar_param;
                // this.ar_code = ar_code;
                try {
                        nya = new GLNyARSingleDetectMarker(ar_param, ar_code, 80.0);
                        nya.setContinueMode(true);
                } catch (NyARException e) {
                        e.printStackTrace();
                }

                mHolder = holder;

                this.fixedBitmap = fixedBitmap;

        }

        @Override
        public int getWidth() {
                return bounds.right;
        }

        @Override
        public int getHeight() {
                return bounds.bottom;
        }

        @Override
        public boolean open() {
                /* nothing to do */
                return true;
        }

        @Override
        public boolean capture(Canvas canvas) {
                if (canvas == null) {
                        throw new IllegalArgumentException("null canvas");
                }

                int[] pixels = this.pixels;
                byte[] buf = this.buf;
                float[] resultf = this.resultf;

                int width = 320;
                int height = 240;
                if (this.w != width || this.h != height || buf == null) {
                        this.w = width;
                        this.h = height;
                        pixels = new int[w * h];
                        buf = new byte[pixels.length * 3];
                        resultf = new float[16];
                }
                int w = this.w;
                int h = this.h;

                Socket socket = null;
                try {
                        Bitmap bitmap = null;
                        if (!LOCAL) {
                                socket = new Socket();
                                socket.setSoTimeout(SOCKET_TIMEOUT);
                                socket.connect(new InetSocketAddress(address, port),
                                                SOCKET_TIMEOUT);
                                // obtain the bitmap
                                InputStream in = socket.getInputStream();
                                // DataInputStream dis = new DataInputStream(
                                // new BufferedInputStream(in, buf.length));
                                // dis.readFully(buf);

                                bitmap = BitmapFactory.decodeStream(in);
                                // bitmap = BitmapFactory.decodeByteArray(buf, 0, buf.length);
                        } else {
                                bitmap = fixedBitmap;
                        }

                        // GL init
                        OpenGLContext glc = new OpenGLContext(OpenGLContext.DEPTH_BUFFER);
                        glc.makeCurrent(mHolder);
                        GL10 gl = (GL10) (glc.getGL());
                        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

                        gl.glViewport(0, 0, w, h);
                        float ratio = (float) h / w;
                        gl.glMatrixMode(GL10.GL_PROJECTION);
                        gl.glLoadIdentity();
                        gl.glFrustumf(-1.0f, 1.0f, -ratio, ratio, 5.0f, 40.0f);
                        // 見る位置
                        gl.glMatrixMode(GL10.GL_MODELVIEW);
                        gl.glLoadIdentity();
                        gl.glTranslatef(0.0f, 0.0f, -10.0f);

                        gl.glDisable(GL10.GL_DITHER);
                        gl.glActiveTexture(GL10.GL_TEXTURE0);
                        gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
                        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
                                        GL10.GL_CLAMP_TO_EDGE);
                        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
                                        GL10.GL_CLAMP_TO_EDGE);
                        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                                        GL10.GL_NEAREST);
                        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                                        GL10.GL_NEAREST);
                        gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
                                        GL10.GL_REPLACE);

                        gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
                        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
                        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
                        gl.glEnable(GL10.GL_CULL_FACE);
                        gl.glShadeModel(GL10.GL_SMOOTH);
                        gl.glEnable(GL10.GL_DEPTH_TEST);

                        boolean is_marker_exist = false;
                        // long time = 0;
                        // double[][] atm = null;

                        if (DETECT) {
                                // time = System.currentTimeMillis();
                                // ここで処理

                                bitmap.getPixels(pixels, 0, w, 0, 0, w, h);

                                for (int i = 0; i < pixels.length; i++) {
                                        int argb = pixels[i];
                                        // byte a = (byte) (argb & 0xFF000000 >> 24);
                                        byte r = (byte) (argb & 0x00FF0000 >> 16);
                                        byte g = (byte) (argb & 0x0000FF00 >> 8);
                                        byte b = (byte) (argb & 0x000000FF);
                                        buf[i * 3] = r;
                                        buf[i * 3 + 1] = g;
                                        buf[i * 3 + 2] = b;
                                }
                                // Log.d("nyar", "Time to copy image : "
                                // + (System.currentTimeMillis() - time) + " ms");

                                if (raster == null) {
                                        raster = new NyARRaster_RGB();
                                }
                                // time = System.currentTimeMillis();
                                NyARRaster_RGB.wrap(raster, buf, w, h);
                                // マーカー検出
                                try {
                                        // Log.d("nyar", "detecting marker");
                                        is_marker_exist = nya.detectMarkerLite(raster, 100);
                                        // Log.d("nyar", "marker detected");

                                        // if (is_marker_exist) {
                                        // 変換行列を取得
                                        // atm = nya.getTransmationMatrix().getArray();
                                        // }
                                } catch (NyARException e) {
                                        Log.e("nyar", "marker detection failed", e);
                                        return false;
                                }
                                // Log.d("nyar", "Time to detect marker : "
                                // + (System.currentTimeMillis() - time) + " ms");
                        } else {
                                gl.glMatrixMode(GL10.GL_MODELVIEW);
                                gl.glLoadIdentity();
                                // int num = (int) (System.currentTimeMillis() % 3) - 1;
                                int num = 0;
                                gl.glTranslatef(0.0f, 0.0f, -10.0f);
                                gl.glRotatef(20.0f * num, 0, 0, 1);
                        }
                        if (is_marker_exist) {
                                // Log.d("nyar", "marker exist");
                                // // Projection transformation.
                                gl.glMatrixMode(GL10.GL_PROJECTION);
                                gl.glLoadIdentity();
                                gl.glLoadMatrixf(ar_param.getCameraFrustumRHf(), 0);
                                gl.glMatrixMode(GL10.GL_MODELVIEW);
                                // Viewing transformation.
                                gl.glLoadIdentity();
                                nya.getCameraViewRH(resultf);
                                // int num = (int) (System.currentTimeMillis() % 3) - 1;
                                // gl.glTranslatef(0.0f, 2.5f, -20.0f);
                                gl.glLoadMatrixf(resultf, 0);
                                // gl.glTranslatef(0.0f, 0.0f, -10.0f);
                                // gl.glRotatef(20.0f, 1, 0, 0);
                                // gl.glScalef(0.5f, 0.5f, 1.0f);
                                // gl.glRotatef(20.0f * num, 0, 0, 1);

                                gl.glFinish();
                        } else {
                                // Log.d("nyar", "marker does not exist");
                        }

                        // time = System.currentTimeMillis();
                        gl.glClearColor(1, 1, 1, 1);
                        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
                        gl.glFinish();
                        // render it to canvas, scaling if necessary
                        if (bounds.right == bitmap.width()
                                        && bounds.bottom == bitmap.height()) {
                                canvas.drawBitmap(bitmap, 0, 0, null);
                        } else {
                                // Log.d("nyar", "preserveAspectRation = " +
                                // preserveAspectRatio);
                                Rect dest;
                                if (preserveAspectRatio) {
                                        dest = new Rect(bounds);
                                        dest.bottom = bitmap.height() * bounds.right
                                                        / bitmap.width();
                                        dest.offset(0, (bounds.bottom - dest.bottom) / 2);
                                } else {
                                        dest = bounds;
                                }
                                canvas.drawBitmap(bitmap, null, dest, paint);
                        }

                        if (is_marker_exist) {
                                // Log.d("nyar", "drawing a cube.");
                                mCube.draw(gl);
                                // gl.glRotatef(20.0f, 0, 0, 1.0f);
                                // mCube.draw(gl);
                        } else if (!DETECT) {
                                // Log.d("nyar", "drawing a cube without detection.");
                                mCube.draw(gl);
                                // Thread.sleep(1000);
                        }
                        gl.glFinish();
                        // Log.d("nyar", "" + (System.currentTimeMillis() - time) + "ms");

                        if (TEXT) {
                                String str = null;
                                // 情報を画面に書く
                                // g.drawImage(img, 32, 32, this);
                                if (is_marker_exist) {
                                        // Log.d("nyar", "marker exist and drawing text");
                                        // str = "マーカー検出 [" + nya.getConfidence() + "]";
                                        // canvas.drawText(str, 32, 100, paint);
                                        // for (int i = 0; i < 3; i++) {
                                        // for (int i2 = 0; i2 < 4; i2++) {
                                        // str = "[" + i + "][" + i2 + "]" + atm[i][i2];
                                        // canvas.drawText(str, 32, 0 + (1 + i2 * 3 + i) * 16,
                                        // paint);
                                        // }
                                        // }

                                        for (int i = 0; i < 4; i++) {
                                                for (int i2 = 0; i2 < 4; i2++) {
                                                        str = "[" + i + "][" + i2 + "]"
                                                                        + resultf[i * 4 + i2];
                                                        canvas.drawText(str, 32, 0 + (1 + i * 4 + i2) * 16,
                                                                        paint);
                                                }
                                        }
                                        float[] arp = ar_param.getCameraFrustumRHf();
                                        for (int i = 0; i < 4; i++) {
                                                for (int i2 = 0; i2 < 4; i2++) {
                                                        str = "[" + i + "][" + i2 + "]" + arp[i * 4 + i2];
                                                        canvas.drawText(str, 152,
                                                                        0 + (1 + i * 4 + i2) * 16, paintBlue);
                                                }
                                        }
                                } else {
                                        // Log.d("nyar", "marker does not exist");
                                        // g.drawString("マーカー未検出:", 32, 100);
                                        str = "マーカー未検出";
                                        canvas.drawText(str, 32, 100, paint);
                                }
                        } // end if
                } catch (Exception e) {
                        Log.i(LOG_TAG, "Failed to obtain image over network", e);
                        return false;
                } finally {
                        try {
                                if (socket != null) {
                                        socket.close();
                                }
                        } catch (IOException e) {
                                /* ignore */
                        }
                }
                return true;
        }

        @Override
        public void close() {
                /* nothing to do */
        }

        class Cube {

                private FloatBuffer mVertexBuffer;
                private IntBuffer mColorBuffer;
                private ByteBuffer mIndexBuffer;

                public Cube() {
                        float fone = 0.5f;
                        float[] vertices = { fone, fone, fone, fone, -fone, fone, -fone,
                                        -fone, fone, -fone, fone, fone, fone, fone, -fone, fone,
                                        -fone, -fone, -fone, -fone, -fone, -fone, fone, -fone };

                        int one = 0x00010000;
                        int[] colors = { 0, 0, 0, one, one, 0, 0, one, one, one, 0, one, 0,
                                        one, 0, one, 0, 0, one, one, one, 0, one, one, one, one,
                                        one, one, 0, one, one, one };

                        byte[] indices = new byte[] { 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2,
                                        2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3, 0,
                                        1, 3, 1, 2 };
                        // indices = new byte[] { 3, 2, 1, 0, 2, 3, 7, 6, 0, 1, 5, 4, 3, 0,
                        // 4,
                        // 7, 1, 2, 6, 5, 4, 5, 6, 7 };

                        // Buffers to be passed to gl*Pointer() functions
                        // must be direct, i.e., they must be placed on the
                        // native heap where the garbage collector cannot
                        // move them.
                        //
                        // Buffers with multi-byte datatypes (e.g., short, int, float)
                        // must have their byte order set to native order

                        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
                        vbb.order(ByteOrder.nativeOrder());
                        mVertexBuffer = vbb.asFloatBuffer();
                        mVertexBuffer.put(vertices);
                        mVertexBuffer.position(0);

                        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
                        cbb.order(ByteOrder.nativeOrder());
                        mColorBuffer = cbb.asIntBuffer();
                        mColorBuffer.put(colors);
                        mColorBuffer.position(0);

                        mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
                        mIndexBuffer.put(indices);
                        mIndexBuffer.position(0);
                }

                public void draw(GL10 gl) {

                        gl.glTranslatef(0.0f, 0.0f, 0.5f); // Place base of cube on marker

                        gl.glFrontFace(GL10.GL_CW);
                        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
                        gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);
                        gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE,
                                        mIndexBuffer);

                        gl.glTranslatef(0.0f, 0.0f, -0.5f); // Place base of cube on marker
                }

        }

}