package org.ourunix.android.jpct.solar;
import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.ourunix.android.GLSurfaceViewActivity;
import org.ourunix.android.R;
import org.ourunix.android.RenderBase;
import com.threed.jpct.*;
import com.threed.jpct.Matrix;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.*;
//http://blog.csdn.net/itde1/article/details/754341
//http://www.jpct.net/jpct-ae/doc/index.html
//http://blog.csdn.net/wangziling100/article/details/7287803
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import org.ourunix.android.jpct.util.Util;
public class SolarRenderer extends RenderBase {
// FrameBuffer对象
private FrameBuffer fb;
// World对象
private World world;
// RGBColor
// private RGBColor back = null;
// Object3D对象
private Object3D plane = null;
private float colors[] = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f };
private FloatBuffer colorBuffer;
public final static int BALL_NUM = 8;
public final static int BALL_RADIUS = 32;
public final static int TRACK_RADIUS = 180;
private Object3D ballIndicator= null;
private Object3D ballCenter = null;
private Object3D ball[] = new Object3D[8];
private Mesh mesh1 = null;
final float TABLE_Y = -60;
// SimpleVector
// 通过设置组件的x,y,z向量来创建一个SimpleVector对象 ,表示小球的运动方向和速度
private SimpleVector move = new SimpleVector(-4.0, 0.0, 4.0);
private boolean fire = true; // 是否击球
private boolean collsion = false;// 是否发生碰撞
private SimpleVector tem;
// FPS
private int fps = 0;
private long time = System.currentTimeMillis();
private GestureDetector gestureDetector;
private int roateDegree = 0;
Context mContext;
// 默认构造
// 对该项目的一些优化
public SolarRenderer(Context context) {
super(context);
mContext = context;
// 传入Resources方法
LoadFile.loadb(context.getResources());
new LoadFile(context.getResources());
// 绘制的最多的Polygon数量,默认为4096,此处如果超过500,则不绘制
Config.maxPolysVisible = 500;
// 最远的合适的平面,默认为1000
Config.farPlane = 1500;
Config.glTransparencyMul = 0.1f;
Config.glTransparencyOffset = 0.1f;
// 使JPCT-AE这个引擎使用顶点而不是顶点数组缓冲对象,因为它可能会使某些硬件更快
// 但在Samsung Galaxy,它并不能工作的很好,可能使之崩溃,这就是它默认为false的原因
Config.useVBO = true;
// back = new RGBColor(50, 50, 100);
Texture.defaultToMipmapping(true);
Texture.defaultTo4bpp(true);
gestureDetector = new GestureDetector(new MyGestureDetector());
}
public void setFire(boolean fire) {
this.fire = fire;
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
try {
if (true) {
move();// 实现上下左右键
if (fire) {
// SimpleVector axis = new SimpleVector(1, 0, 1);// 球旋转时轴的方向
// ball1.rotateAxis(axis, (float) Math.toRadians(10));// 实现球旋转
}
// 以定义好的RGBColor清屏
// fb.clear(back);
fb.clear();
// 变换和灯光所有的多 边形
world.renderScene(fb);
// 绘制由renderScene产生的场景
world.draw(fb);
// 渲染显示图像
fb.display();
// fps加1
fps += 1;
// 打印输出fps
if (System.currentTimeMillis() - time > 1000) {
System.out.println(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
} else {
if (fb != null) {
fb.dispose();
fb = null;
}
}
} catch (Exception e) {
e.printStackTrace();
// 打印异常信息
Logger.log("Drawing thread terminated!", Logger.MESSAGE);
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
if (fb != null) {
fb = null;
}
// 新产生一个FrameBuffer对象
fb = new FrameBuffer(gl, width, height);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
Logger.log("onCreate");
colorBuffer = Util.createFloatBuffer(colors);
// 混合渲染
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
// 新建world对象
world = new World();
// 纹理
//AndroidRuntime com.threed.jpct.Texture.loadTexture
//That's because you are loading it as a Drawable. Don't do that. Drawables will be scaled by Android under some circumstances. Use either bitmaps or an inputstream instead.
TextureManager tm = TextureManager.getInstance();
Texture texture2 = new Texture(LoadFile.bitmap1);
Texture texture3 = new Texture(LoadFile.bitmap2);
Texture texture4 = new Texture(LoadFile.bitmap3);
tm.addTexture("texture2", texture2);
tm.addTexture("texture3", texture3);
tm.addTexture("texture4",texture4);
// 初始化各3D元素
plane = Primitives.getPlane(20, 10); // 得到平面
// 也可以采用上面得到平面的方法,这里采用的是加载3ds模型
plane = loadModel("table.3ds", 4f);
plane.translate(0, -30, 20);
plane.rotateX(-(float) Math.PI / 2); // 从jpct-ae的坐标旋转到正常坐标系
plane.rotateY((float) Math.PI / 2);
world.addObject(plane);
// 设置纹理贴图方式
ballIndicator = Primitives.getSphere(BALL_RADIUS); // 得到球体
ballIndicator.translate(0,TABLE_Y,-TRACK_RADIUS);
world.addObject(ballIndicator);
ballIndicator.setVisibility(false);
ballCenter = Primitives.getSphere(BALL_RADIUS); // 得到球体
ballCenter.translate(0,TABLE_Y,0);
ballCenter.calcTextureWrapSpherical();
ballCenter.setTexture("texture4");
world.addObject(ballCenter);
ballCenter.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
for (int i = 0; i < BALL_NUM; i++) {
ball[i] = Primitives.getSphere(BALL_RADIUS); // 得到球体
ball[i].translate(((int) (TRACK_RADIUS * Math.sin(Math.toRadians(i * 45)))),
TABLE_Y, ((int) (TRACK_RADIUS * Math.cos(Math.toRadians(i * 45)))));
ball[i].calcTextureWrapSpherical();
ball[i].setTexture("texture3");
world.addObject(ball[i]);
ball[i].setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
}
// 设置碰撞模式
plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
// 设置环境光
world.setAmbientLight(255, 255, 255);
// 这里设置光照的地方不成功,不能显示光照,不知道为什么????????????
// 设置光照
Light light = new Light(world);
light.setPosition(new SimpleVector(ballIndicator.getTransformedCenter().x,
ballIndicator.getTransformedCenter().y - 100, ballIndicator
.getTransformedCenter().z - 50));
light.setIntensity(255, 0, 0);
// 以上3段代码没有效果
// 编译所有对象
world.buildAllObjects();
// Camera相关
Camera cam = world.getCamera();
cam.setPositionToCenter(ballIndicator);
cam.align(ballIndicator);// 将相机方向对着物体的Z轴正方向
// 相机绕着X轴旋转20度
cam.rotateCameraX((float) Math.toRadians(40));
cam.moveCamera(Camera.CAMERA_MOVEOUT, 500);
// 向外以移动
cam.moveCamera(Camera.CAMERA_MOVEUP, 60);
// cam.lookAt(plane.getTransformedCenter());
// 回收内存
MemoryHelper.compact();
}
// 载入模型
private Object3D loadModel(String filename, float scale) {
// 将载入的3ds文件保存到model数组中
Object3D[] model = Loader.load3DS(LoadFile.loadf(filename), scale);
// 取第一个3ds文件
Object3D o3d = new Object3D(0);
// 临时变量temp
Object3D temp = null;
// 遍历model数组
for (int i = 0; i < model.length; i++) {
// 给temp赋予model数组中的某一个
temp = model[i];
// 设置temp的中心为 origin (0,0,0)
temp.setCenter(SimpleVector.ORIGIN);
// 沿x轴旋转坐标系到正常的坐标系(jpct-ae的坐标中的y,x是反的)
temp.rotateX((float) (-.5 * Math.PI));
// 使用旋转矩阵指定此对象旋转网格的原始数据
temp.rotateMesh();
// new 一个矩阵来作为旋转矩阵
temp.setRotationMatrix(new Matrix());
// 合并o3d与temp
o3d = Object3D.mergeObjects(o3d, temp);
// 主要是为了从桌面版JPCT到android版的移徝(桌面版此处为o3d.build())
o3d.compile();
}
// 返回o3d对象
return o3d;
}
@Override
public void leftSwipe() {
Log.d(TAG, "---onTouchEvent action:ACTION_LEFT");
roateDegree+=10;
roateDegree%=360;
for (int i = 0; i < BALL_NUM; i++) {
ball[i].clearTranslation();
ball[i].translate(((int) (TRACK_RADIUS* Math.sin(Math.toRadians(( i * 45 +roateDegree)%360)))),
TABLE_Y, ((int) (TRACK_RADIUS * Math.cos(Math.toRadians((i * 45 +roateDegree)%360)))));
}
super.leftSwipe();
}
@Override
public void rightSwipe() {
roateDegree-=10;
if(roateDegree<0){
roateDegree+=360;
}
Log.d(TAG, "---onTouchEvent action:ACTION_RIGHT");
for (int i = 0; i < BALL_NUM; i++) {
ball[i].clearTranslation();
ball[i].translate(((int) (TRACK_RADIUS * Math.sin(Math.toRadians((i * 45 +roateDegree)%360)))),
TABLE_Y, ((int) (TRACK_RADIUS * Math.cos(Math.toRadians((i * 45 +roateDegree)%360)))));
}
super.rightSwipe();
}
public void upSwipe(){}
public void downSwipe(){}
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
public final static String TAG="TAG";
float downX = 0;
float downY = 0;
float upX = 0;
float upY = 0;
@Override
public boolean handleTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// swipe horizontal?
if(Math.abs(deltaX) > SWIPE_MIN_DISTANCE){
// left or right
if(deltaX < 0) { rightSwipe(); }
if(deltaX > 0) { leftSwipe(); }
}
else {
Log.i(TAG, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + SWIPE_MIN_DISTANCE);
return false; // We don't consume the event
}
// swipe vertical?
if(Math.abs(deltaY) > SWIPE_MIN_DISTANCE){
// top or down
if(deltaY < 0) { downSwipe(); }
if(deltaY > 0) { upSwipe();}
}
else {
Log.i(TAG, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + SWIPE_MIN_DISTANCE);
return false; // We don't consume the event
}
break;
case MotionEvent.ACTION_UP:
//Log.d(TAG, "---onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
// Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");
break;
}
return super.handleTouchEvent(event);
}
public void move() {
Camera cam = world.getCamera();
if (GLSurfaceViewActivity.up) { // 按向上方向键
cam.moveCamera(cam.getDirection(), -2);// 摄像机向里面移动
}
if (GLSurfaceViewActivity.down) {
cam.moveCamera(cam.getDirection(), 2);// 向外移动
}
if (GLSurfaceViewActivity.left) {
plane.rotateY((float) Math.toRadians(-10));// 向左旋转
}
if (GLSurfaceViewActivity.right) {
plane.rotateY((float) Math.toRadians(10)); // 向右旋转
}
}
}
// 载入文件
class LoadFile {
public static Resources resource;
public static Bitmap bitmap1;
public static Bitmap bitmap2;
public static Bitmap bitmap3;
public LoadFile(Resources res) {
resource = res;
}
// 载入模型
public static InputStream loadf(String fileName) {
AssetManager am = LoadFile.resource.getAssets();
try {
return am.open(fileName);
} catch (IOException e) {
return null;
}
}
// 载入纹理图片
public static void loadb(Resources res) {
bitmap1 = BitmapFactory.decodeResource(res, R.raw.table);
bitmap2 = BitmapFactory.decodeResource(res, R.raw.bool1);
bitmap3 = BitmapFactory.decodeResource(res, R.raw.bool2);
}
}