/*
* 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
}
}
}