diff --git a/app/build.gradle b/app/build.gradle
index 97a4bcd6..b0c072ce 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,8 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 23
- buildToolsVersion '25.0.0'
+ compileSdkVersion 25
+ buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.asha.md360player4android"
@@ -23,9 +23,11 @@ android {
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:23.2.0'
+ compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.squareup.picasso:picasso:2.5.2'
//required, enough for most devices.
+ compile 'com.android.support:recyclerview-v7:25.3.1'
+ compile 'com.android.support:cardview-v7:25.3.1'
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.6.0'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.6.0'
compile project(path: ':vrlib')
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 64e02076..4c72f50d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,6 +21,8 @@
+
+
diff --git a/app/src/main/java/com/asha/md360player4android/CubemapPlayerActivity.java b/app/src/main/java/com/asha/md360player4android/CubemapPlayerActivity.java
new file mode 100644
index 00000000..f092f8d9
--- /dev/null
+++ b/app/src/main/java/com/asha/md360player4android/CubemapPlayerActivity.java
@@ -0,0 +1,152 @@
+package com.asha.md360player4android;
+
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.DrawableRes;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.asha.vrlib.MDVRLibrary;
+import com.asha.vrlib.model.MDRay;
+import com.asha.vrlib.plugins.hotspot.IMDHotspot;
+import com.asha.vrlib.texture.MD360BitmapTexture;
+import com.asha.vrlib.texture.MD360CubemapTexture;
+import com.squareup.picasso.Picasso;
+import com.squareup.picasso.Target;
+
+import static com.squareup.picasso.MemoryPolicy.NO_CACHE;
+import static com.squareup.picasso.MemoryPolicy.NO_STORE;
+
+/**
+ * Created by hzqiujiadi on 16/4/5.
+ * hzqiujiadi ashqalcn@gmail.com
+ */
+public class CubemapPlayerActivity extends MD360PlayerActivity {
+
+ private static final String TAG = "BitmapPlayerActivity";
+
+ private Uri nextUri = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ findViewById(R.id.control_next).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ busy();
+ //nextUri = getDrawableUri(R.drawable.texture);
+ getVRLibrary().notifyPlayerChanged();
+ }
+ });
+ }
+
+ private Target mTarget;// keep the reference for picasso.
+
+ private void loadImage(Uri uri, final MD360CubemapTexture.Callback callback){
+ mTarget = new Target() {
+ @Override
+ public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
+ Log.d(TAG, "loaded image, size:" + bitmap.getWidth() + "," + bitmap.getHeight());
+
+ // notify if size changed
+ getVRLibrary().onTextureResize(bitmap.getWidth(), bitmap.getHeight());
+
+ // texture
+ callback.texture(bitmap);
+ //cancelBusy();
+ }
+
+ @Override
+ public void onBitmapFailed(Drawable errorDrawable) {
+
+ }
+
+ @Override
+ public void onPrepareLoad(Drawable placeHolderDrawable) {
+
+ }
+ };
+
+ Log.d(TAG, "load image with max texture size:" + callback.getMaxTextureSize());
+ Picasso.with(getApplicationContext())
+ .load(uri)
+ .resize(callback.getMaxTextureSize(),callback.getMaxTextureSize())
+ .onlyScaleDown()
+ .centerInside()
+ .memoryPolicy(NO_CACHE, NO_STORE)
+ .into(mTarget);
+ }
+
+ private Uri currentUri(){
+ if (nextUri == null){
+ return getUri();
+ } else {
+ return nextUri;
+ }
+ }
+
+ @Override
+ protected MDVRLibrary createVRLibrary() {
+ return MDVRLibrary.with(this)
+ .displayMode(MDVRLibrary.DISPLAY_MODE_NORMAL)
+ .interactiveMode(MDVRLibrary.INTERACTIVE_MODE_TOUCH)
+ .projectionMode(MDVRLibrary.PROJECTION_MODE_CUBE) // needed
+ .asCubemap(new MDVRLibrary.ICubemapProvider() {
+ @Override
+ public void onProvideCubemap(MD360CubemapTexture.Callback callback, int cubeFace) {
+ Log.d(TAG, "Load face: " + cubeFace);
+
+ switch(cubeFace) {
+ case MD360CubemapTexture.CUBE_FRONT:
+ nextUri = getDrawableUri(R.drawable.cube_front);
+ break;
+ case MD360CubemapTexture.CUBE_BACK:
+ nextUri = getDrawableUri(R.drawable.cube_back);
+ break;
+ case MD360CubemapTexture.CUBE_TOP:
+ nextUri = getDrawableUri(R.drawable.cube_top);
+ break;
+ case MD360CubemapTexture.CUBE_BOTTOM:
+ nextUri = getDrawableUri(R.drawable.cube_bottom);
+ break;
+ case MD360CubemapTexture.CUBE_LEFT:
+ nextUri = getDrawableUri(R.drawable.cube_left);
+ break;
+ case MD360CubemapTexture.CUBE_RIGHT:
+ nextUri = getDrawableUri(R.drawable.cube_right);
+ break;
+ default:
+ return;
+ }
+
+ loadImage(currentUri(), callback);
+ }
+
+ @Override
+ public void onReady() {
+ // This can be used to hide a loading view and show the library view
+ Toast.makeText(CubemapPlayerActivity.this, "CubeMap Ready", Toast.LENGTH_SHORT).show();
+ cancelBusy();
+ }
+ })
+ .listenTouchPick(new MDVRLibrary.ITouchPickListener() {
+ @Override
+ public void onHotspotHit(IMDHotspot hitHotspot, MDRay ray) {
+ Log.d(TAG,"Ray:" + ray + ", hitHotspot:" + hitHotspot);
+ }
+ })
+ .pinchEnabled(true)
+ .build(findViewById(R.id.gl_view));
+ }
+
+ private Uri getDrawableUri(@DrawableRes int resId){
+ Resources resources = getResources();
+ return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + resources.getResourcePackageName(resId) + '/' + resources.getResourceTypeName(resId) + '/' + resources.getResourceEntryName(resId) );
+ }
+}
diff --git a/app/src/main/java/com/asha/md360player4android/DemoActivity.java b/app/src/main/java/com/asha/md360player4android/DemoActivity.java
index ce256021..f86af0f0 100644
--- a/app/src/main/java/com/asha/md360player4android/DemoActivity.java
+++ b/app/src/main/java/com/asha/md360player4android/DemoActivity.java
@@ -105,6 +105,22 @@ public void onClick(View v) {
}
}
});
+
+ findViewById(R.id.cubemap_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String url = et.getText().toString();
+
+ MD360PlayerActivity.startCubemap(DemoActivity.this, null);
+ }
+ });
+
+ findViewById(R.id.recycler_view_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ RecyclerViewActivity.start(DemoActivity.this);
+ }
+ });
}
private Uri getDrawableUri(@DrawableRes int resId){
diff --git a/app/src/main/java/com/asha/md360player4android/MD360PlayerActivity.java b/app/src/main/java/com/asha/md360player4android/MD360PlayerActivity.java
index d708f8d0..1c2549d6 100644
--- a/app/src/main/java/com/asha/md360player4android/MD360PlayerActivity.java
+++ b/app/src/main/java/com/asha/md360player4android/MD360PlayerActivity.java
@@ -21,6 +21,7 @@
import com.asha.vrlib.MDDirectorCamUpdate;
import com.asha.vrlib.MDVRLibrary;
+import com.asha.vrlib.model.MDHitEvent;
import com.asha.vrlib.model.MDHotspotBuilder;
import com.asha.vrlib.model.MDPosition;
import com.asha.vrlib.model.MDRay;
@@ -105,6 +106,10 @@ public static void startBitmap(Context context, Uri uri){
start(context, uri, BitmapPlayerActivity.class);
}
+ public static void startCubemap(Context context, Uri uri){
+ start(context, uri, CubemapPlayerActivity.class);
+ }
+
private static void start(Context context, Uri uri, Class extends Activity> clz){
Intent i = new Intent(context,clz);
i.setData(uri);
@@ -363,9 +368,11 @@ public void onClick(View v) {
final TextView hotspotText = (TextView) findViewById(R.id.hotspot_text);
final TextView directorBriefText = (TextView) findViewById(R.id.director_brief_text);
- getVRLibrary().setEyePickChangedListener(new MDVRLibrary.IEyePickListener() {
+ getVRLibrary().setEyePickChangedListener(new MDVRLibrary.IEyePickListener2() {
@Override
- public void onHotspotHit(IMDHotspot hotspot, long hitTimestamp) {
+ public void onHotspotHit(MDHitEvent hitEvent) {
+ IMDHotspot hotspot = hitEvent.getHotspot();
+ long hitTimestamp = hitEvent.getTimestamp();
String text = hotspot == null ? "nop" : String.format(Locale.CHINESE, "%s %fs", hotspot.getTitle(), (System.currentTimeMillis() - hitTimestamp) / 1000.0f );
hotspotText.setText(text);
diff --git a/app/src/main/java/com/asha/md360player4android/RecyclerViewActivity.java b/app/src/main/java/com/asha/md360player4android/RecyclerViewActivity.java
new file mode 100644
index 00000000..d9558621
--- /dev/null
+++ b/app/src/main/java/com/asha/md360player4android/RecyclerViewActivity.java
@@ -0,0 +1,235 @@
+package com.asha.md360player4android;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.DrawableRes;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.asha.vrlib.MDVRLibrary;
+import com.asha.vrlib.model.MDHitEvent;
+import com.asha.vrlib.texture.MD360BitmapTexture;
+import com.google.android.apps.muzei.render.GLTextureView;
+import com.squareup.picasso.Picasso;
+import com.squareup.picasso.Target;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RecyclerViewActivity extends AppCompatActivity {
+
+ private static final String TAG = "MainActivity";
+
+ private Uri[] sMockData;
+
+ private VRLibManager manager;
+
+ public static void start(Context context) {
+ Intent i = new Intent(context, RecyclerViewActivity.class);
+ context.startActivity(i);
+ }
+
+ public RecyclerViewActivity() {}
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ sMockData = new Uri[] {
+ getDrawableUri(R.drawable.bitmap360)
+ ,getDrawableUri(R.drawable.texture)
+ };
+
+ setContentView(R.layout.activity_main);
+ manager = new VRLibManager(this);
+
+ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
+ final FeedAdapter adapter = new FeedAdapter();
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setItemAnimator(null);
+ recyclerView.setAdapter(adapter);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ manager.fireResumed();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ manager.firePaused();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ manager.fireDestroy();
+ }
+
+ private static class FeedModel {
+
+ private final Uri uri;
+ private final int type;
+
+ public FeedModel(int type, Uri uri) {
+ this.type = type;
+ this.uri = uri;
+ }
+ }
+
+ private abstract class FeedVH extends RecyclerView.ViewHolder {
+
+ public FeedVH(ViewGroup vp, int layoutId) {
+ super(create(vp, layoutId));
+ }
+
+ public abstract void bind(FeedModel feedModel);
+ }
+
+ private class FeedTextVH extends FeedVH {
+
+ public FeedTextVH(ViewGroup vp) {
+ super(vp, R.layout.feed_text_layout);
+ }
+
+ @Override
+ public void bind(FeedModel feedModel) {
+ }
+ }
+
+ private class FeedVRVH extends FeedVH implements MDVRLibrary.IBitmapProvider {
+
+ private TextView text;
+
+ private GLTextureView glTextureView;
+
+ private ViewGroup parent;
+
+ private MDVRLibrary vrlib;
+
+ private FeedModel model;
+
+ private long ts;
+
+ public FeedVRVH(ViewGroup vp) {
+ super(vp, R.layout.feed_panorama_layout);
+ text = (TextView) itemView.findViewById(R.id.feed_text);
+ glTextureView = (GLTextureView) itemView.findViewById(R.id.feed_texture_view);
+ parent = (ViewGroup) glTextureView.getParent();
+ }
+
+ @Override
+ public void bind(FeedModel model) {
+ this.model = model;
+ ensureVRLib();
+ vrlib.notifyPlayerChanged();
+ }
+
+ private void ensureVRLib() {
+ if (vrlib == null) {
+ vrlib = manager.create(this, glTextureView);
+ vrlib.setEyePickChangedListener(new MDVRLibrary.IEyePickListener2() {
+ @Override
+ public void onHotspotHit(MDHitEvent hitEvent) {
+ long delta = System.currentTimeMillis() - ts;
+ if (delta < 500) {
+ return;
+ }
+
+ String brief = vrlib.getDirectorBrief().toString();
+ text.setText(brief);
+ ts = System.currentTimeMillis();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onProvideBitmap(final MD360BitmapTexture.Callback callback) {
+ if (model == null) {
+ return;
+ }
+
+ Picasso.with(itemView.getContext()).load(model.uri).into(new Target() {
+ @Override
+ public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
+ vrlib.onTextureResize(bitmap.getWidth(), bitmap.getHeight());
+ callback.texture(bitmap);
+ }
+
+ @Override
+ public void onBitmapFailed(Drawable errorDrawable) {
+
+ }
+
+ @Override
+ public void onPrepareLoad(Drawable placeHolderDrawable) {
+
+ }
+ });
+ }
+ }
+
+ private Uri getDrawableUri(@DrawableRes int resId){
+ Resources resources = getResources();
+ return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + resources.getResourcePackageName(resId) + '/' + resources.getResourceTypeName(resId) + '/' + resources.getResourceEntryName(resId) );
+ }
+
+ private class FeedAdapter extends RecyclerView.Adapter {
+
+ private List feeds = new ArrayList<>();
+
+ public FeedAdapter() {
+ int i = 0;
+ while (i++ < 50) {
+ Uri uri = sMockData[(int) (Math.random() * sMockData.length)];
+ feeds.add(new FeedModel(Math.random() > 0.3 ? 0 : 1, uri));
+ }
+ }
+
+ @Override
+ public FeedVH onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == 0) {
+ return new FeedVRVH(parent);
+ } else {
+ return new FeedTextVH(parent);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(FeedVH holder, int position) {
+ holder.bind(feeds.get(position));
+ }
+
+ @Override
+ public void onViewRecycled(FeedVH holder) {
+ super.onViewRecycled(holder);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return feeds.get(position).type;
+ }
+
+ @Override
+ public int getItemCount() {
+ return feeds.size();
+ }
+ }
+
+ private static View create(ViewGroup vp, int layout) {
+ return LayoutInflater.from(vp.getContext()).inflate(layout, vp, false);
+ }
+}
diff --git a/app/src/main/java/com/asha/md360player4android/VRLibManager.java b/app/src/main/java/com/asha/md360player4android/VRLibManager.java
new file mode 100644
index 00000000..d9212a7d
--- /dev/null
+++ b/app/src/main/java/com/asha/md360player4android/VRLibManager.java
@@ -0,0 +1,68 @@
+package com.asha.md360player4android;
+
+import android.content.Context;
+
+import com.asha.vrlib.MDVRLibrary;
+import com.asha.vrlib.model.MDPinchConfig;
+import com.google.android.apps.muzei.render.GLTextureView;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.asha.vrlib.MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION_WITH_TOUCH;
+
+/**
+ * Created by hzqiujiadi on 2017/9/7.
+ * hzqiujiadi ashqalcn@gmail.com
+ */
+
+public class VRLibManager {
+ private Context context;
+
+ private boolean isResumed;
+
+ private List libs = new LinkedList<>();
+
+ public VRLibManager(Context context) {
+ this.context = context;
+ }
+
+ public MDVRLibrary create(MDVRLibrary.IBitmapProvider provider, GLTextureView textureView) {
+ MDVRLibrary lib = MDVRLibrary.with(context)
+ .asBitmap(provider)
+ .pinchConfig(new MDPinchConfig().setMin(0.8f).setSensitivity(1).setDefaultValue(0.8f))
+ .touchSensitivity(2)
+ .interactiveMode(INTERACTIVE_MODE_CARDBORAD_MOTION_WITH_TOUCH)
+ .build(textureView);
+ add(lib);
+ return lib;
+ }
+
+ private void add(MDVRLibrary lib) {
+ if (isResumed) {
+ lib.onResume(context);
+ }
+
+ libs.add(lib);
+ }
+
+ public void fireResumed() {
+ isResumed = true;
+ for (MDVRLibrary library : libs) {
+ library.onResume(context);
+ }
+ }
+
+ public void firePaused() {
+ isResumed = false;
+ for (MDVRLibrary library : libs) {
+ library.onPause(context);
+ }
+ }
+
+ public void fireDestroy() {
+ for (MDVRLibrary library : libs) {
+ library.onDestroy();
+ }
+ }
+}
diff --git a/app/src/main/res/drawable-xhdpi/cube_back.jpg b/app/src/main/res/drawable-xhdpi/cube_back.jpg
new file mode 100644
index 00000000..4e17b779
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_back.jpg differ
diff --git a/app/src/main/res/drawable-xhdpi/cube_bottom.jpg b/app/src/main/res/drawable-xhdpi/cube_bottom.jpg
new file mode 100644
index 00000000..893f3947
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_bottom.jpg differ
diff --git a/app/src/main/res/drawable-xhdpi/cube_front.jpg b/app/src/main/res/drawable-xhdpi/cube_front.jpg
new file mode 100644
index 00000000..470a6797
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_front.jpg differ
diff --git a/app/src/main/res/drawable-xhdpi/cube_left.jpg b/app/src/main/res/drawable-xhdpi/cube_left.jpg
new file mode 100644
index 00000000..5750b91a
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_left.jpg differ
diff --git a/app/src/main/res/drawable-xhdpi/cube_right.jpg b/app/src/main/res/drawable-xhdpi/cube_right.jpg
new file mode 100644
index 00000000..89630371
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_right.jpg differ
diff --git a/app/src/main/res/drawable-xhdpi/cube_top.jpg b/app/src/main/res/drawable-xhdpi/cube_top.jpg
new file mode 100644
index 00000000..4db3c2a3
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/cube_top.jpg differ
diff --git a/app/src/main/res/layout/activity_demo.xml b/app/src/main/res/layout/activity_demo.xml
index 83d2b450..a8b366db 100644
--- a/app/src/main/res/layout/activity_demo.xml
+++ b/app/src/main/res/layout/activity_demo.xml
@@ -37,6 +37,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..7eb1449e
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_md_using_surface_view.xml b/app/src/main/res/layout/activity_md_using_surface_view.xml
index ebd369ff..8cd26aae 100644
--- a/app/src/main/res/layout/activity_md_using_surface_view.xml
+++ b/app/src/main/res/layout/activity_md_using_surface_view.xml
@@ -36,254 +36,224 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/feed_text_layout.xml b/app/src/main/res/layout/feed_text_layout.xml
new file mode 100644
index 00000000..b2863ad2
--- /dev/null
+++ b/app/src/main/res/layout/feed_text_layout.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vrlib/build.gradle b/vrlib/build.gradle
index 60fa43b5..f19a331c 100644
--- a/vrlib/build.gradle
+++ b/vrlib/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
android {
- compileSdkVersion 23
- buildToolsVersion '25.0.0'
+ compileSdkVersion 25
+ buildToolsVersion '25.0.2'
defaultConfig {
minSdkVersion 15
- targetSdkVersion 23
+ targetSdkVersion 25
versionCode 6
versionName "1.0.1"
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/MD360Director.java b/vrlib/src/main/java/com/asha/vrlib/MD360Director.java
index 7ea7bf50..d3b054aa 100644
--- a/vrlib/src/main/java/com/asha/vrlib/MD360Director.java
+++ b/vrlib/src/main/java/com/asha/vrlib/MD360Director.java
@@ -232,6 +232,13 @@ private void updateWorldRotationMatrix(){
// call in gl thread
public void updateSensorMatrix(float[] sensorMatrix) {
+ if (sensorMatrix == null
+ || sensorMatrix.length != 16
+ || Float.isNaN(sensorMatrix[0])
+ || Float.isNaN(sensorMatrix[1])) {
+ return;
+ }
+
System.arraycopy(sensorMatrix, 0, mSensorMatrix, 0, 16);
mWorldRotationMatrixInvalidate = true;
}
@@ -239,7 +246,7 @@ public void updateSensorMatrix(float[] sensorMatrix) {
// call in gl thread
public void reset(){
mDeltaX = mDeltaY = 0;
- Matrix.setIdentityM(mSensorMatrix,0);
+ Matrix.setIdentityM(mSensorMatrix, 0);
mWorldRotationMatrixInvalidate = true;
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/MD360Program.java b/vrlib/src/main/java/com/asha/vrlib/MD360Program.java
index 870c5c4d..81d502b1 100644
--- a/vrlib/src/main/java/com/asha/vrlib/MD360Program.java
+++ b/vrlib/src/main/java/com/asha/vrlib/MD360Program.java
@@ -20,6 +20,7 @@ public class MD360Program {
private int mProgramHandle;
private int mSTMatrixHandle;
private int mUseTextureTransformHandle;
+ private int mIsSkyboxHandle;
private int mContentType;
public MD360Program(int type) {
@@ -53,6 +54,7 @@ public void build(Context context){
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
mSTMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_STMatrix");
mUseTextureTransformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_UseSTM");
+ mIsSkyboxHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_IsSkybox");
}
protected String getVertexShader(Context context){
@@ -91,6 +93,10 @@ public int getUseTextureTransformHandle() {
return mUseTextureTransformHandle;
}
+ public int getIsSkyboxHandle() {
+ return mIsSkyboxHandle;
+ }
+
public int getTextureCoordinateHandle() {
return mTextureCoordinateHandle;
}
@@ -106,6 +112,9 @@ static String fs(Context context, int type){
case MDVRLibrary.ContentType.FBO:
resId = R.raw.per_pixel_fragment_shader_bitmap_fbo;
break;
+ case MDVRLibrary.ContentType.CUBEMAP:
+ resId = R.raw.per_pixel_fragment_shader_cubemap;
+ break;
case MDVRLibrary.ContentType.VIDEO:
default:
resId = R.raw.per_pixel_fragment_shader;
diff --git a/vrlib/src/main/java/com/asha/vrlib/MD360Renderer.java b/vrlib/src/main/java/com/asha/vrlib/MD360Renderer.java
index f9045e02..26a32094 100644
--- a/vrlib/src/main/java/com/asha/vrlib/MD360Renderer.java
+++ b/vrlib/src/main/java/com/asha/vrlib/MD360Renderer.java
@@ -82,7 +82,7 @@ public void onDrawFrame(GL10 glUnused){
mGLHandler.dealMessage();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
- glCheck("MD360Renderer onDrawFrame 1");
+ glCheck("MD360Renderer onDrawFrame begin. ");
int size = mDisplayModeManager.getVisibleSize();
@@ -126,7 +126,8 @@ public void onDrawFrame(GL10 glUnused){
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
}
- mMainLinePipe.commit(mWidth,mHeight,size);
+ mMainLinePipe.commit(mWidth, mHeight, size);
+ glCheck("MD360Renderer onDrawFrame end. ");
// mFps.step();
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/MDTouchHelper.java b/vrlib/src/main/java/com/asha/vrlib/MDTouchHelper.java
index 82af566b..f9ba843c 100644
--- a/vrlib/src/main/java/com/asha/vrlib/MDTouchHelper.java
+++ b/vrlib/src/main/java/com/asha/vrlib/MDTouchHelper.java
@@ -39,6 +39,7 @@ public class MDTouchHelper {
private static final int MODE_INIT = 0;
private static final int MODE_PINCH = 1;
+ private float mTouchSensitivity;
public MDTouchHelper(Context context) {
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@@ -57,7 +58,7 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d
if (mCurrentMode == MODE_PINCH) return false;
if (mAdvanceGestureListener != null){
- mAdvanceGestureListener.onDrag(distanceX / mGlobalScale, distanceY / mGlobalScale);
+ mAdvanceGestureListener.onDrag(scaled(distanceX), scaled(distanceY));
}
return true;
}
@@ -73,6 +74,10 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve
});
}
+ private float scaled(float input) {
+ return input / mGlobalScale * mTouchSensitivity;
+ }
+
private void animCancel(){
if (valueAnimator != null){
valueAnimator.cancel();
@@ -98,7 +103,7 @@ public void onAnimationUpdate(ValueAnimator animation) {
lastTime = now;
if (mAdvanceGestureListener != null){
- mAdvanceGestureListener.onDrag(sx / mGlobalScale, sy / mGlobalScale);
+ mAdvanceGestureListener.onDrag(scaled(sx), scaled(sy));
}
}
});
@@ -213,6 +218,10 @@ public void setFlingConfig(MDFlingConfig flingConfig) {
this.mFlingConfig = flingConfig;
}
+ public void setTouchSensitivity(float touchSensitivity) {
+ this.mTouchSensitivity = touchSensitivity;
+ }
+
private class PinchInfo{
private float x1;
private float y1;
@@ -234,7 +243,7 @@ public void mark(float x1, float y1, float x2, float y2){
public float pinch(float distance) {
if (oDistance == 0) oDistance = distance;
float scale = distance / oDistance - 1;
- scale *= mSensitivity;
+ scale *= mSensitivity * 3;
currentScale = prevScale + scale;
// range
currentScale = Math.max(currentScale, minScale);
diff --git a/vrlib/src/main/java/com/asha/vrlib/MDVRLibrary.java b/vrlib/src/main/java/com/asha/vrlib/MDVRLibrary.java
index 37f09107..0ba7a1ba 100644
--- a/vrlib/src/main/java/com/asha/vrlib/MDVRLibrary.java
+++ b/vrlib/src/main/java/com/asha/vrlib/MDVRLibrary.java
@@ -33,6 +33,7 @@
import com.asha.vrlib.strategy.projection.IMDProjectionFactory;
import com.asha.vrlib.strategy.projection.ProjectionModeManager;
import com.asha.vrlib.texture.MD360BitmapTexture;
+import com.asha.vrlib.texture.MD360CubemapTexture;
import com.asha.vrlib.texture.MD360Texture;
import com.asha.vrlib.texture.MD360VideoTexture;
import com.google.android.apps.muzei.render.GLTextureView;
@@ -80,6 +81,7 @@ public class MDVRLibrary {
public static final int PROJECTION_MODE_MULTI_FISH_EYE_VERTICAL = 211;
public static final int PROJECTION_MODE_STEREO_SPHERE_HORIZONTAL = 212;
public static final int PROJECTION_MODE_STEREO_SPHERE_VERTICAL = 213;
+ public static final int PROJECTION_MODE_CUBE = 214;
private RectF mTextureSize = new RectF(0, 0, 1024, 1024);
private InteractiveModeManager mInteractiveModeManager;
@@ -147,6 +149,8 @@ public void onPinch(final float scale) {
mTouchHelper.setFlingEnabled(builder.flingEnabled);
mTouchHelper.setFlingConfig(builder.flingConfig);
+ mTouchHelper.setTouchSensitivity(builder.touchSensitivity);
+
mScreenWrapper.getView().setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
@@ -286,7 +290,7 @@ public void switchDisplayMode(final Context context){
/**
* Switch Display Mode
*
- * @param activity activity
+ * @param context context
* @param mode mode
*
* {@link #DISPLAY_MODE_GLASS}
@@ -505,6 +509,11 @@ public interface IBitmapProvider {
void onProvideBitmap(MD360BitmapTexture.Callback callback);
}
+ public interface ICubemapProvider {
+ void onProvideCubemap(MD360CubemapTexture.Callback callback, int cubeFace);
+ void onReady();
+ }
+
public interface IImageLoadProvider {
void onProvideBitmap(Uri uri, MD360BitmapTexture.Callback callback);
}
@@ -604,6 +613,7 @@ public static class Builder {
private IDirectorFilter directorFilter;
private boolean flingEnabled = true; // default true
private MDFlingConfig flingConfig;
+ private float touchSensitivity = 1; // default = 1
private Builder(Context context) {
this.context = context;
@@ -642,6 +652,13 @@ public Builder asBitmap(IBitmapProvider bitmapProvider){
return this;
}
+ public Builder asCubemap(ICubemapProvider cubemapProvider){
+ notNull(cubemapProvider, "cubemap Provider can't be null!");
+ texture = new MD360CubemapTexture(cubemapProvider);
+ contentType = ContentType.CUBEMAP;
+ return this;
+ }
+
/**
* gesture listener, e.g.
* onClick
@@ -770,6 +787,11 @@ public Builder flingConfig(MDFlingConfig config){
return this;
}
+ public Builder touchSensitivity(float touchSensitivity){
+ this.touchSensitivity = touchSensitivity;
+ return this;
+ }
+
/**
* build it!
*
@@ -809,6 +831,7 @@ public interface ContentType {
int VIDEO = 0;
int BITMAP = 1;
int FBO = 2;
+ int CUBEMAP = 3;
int DEFAULT = VIDEO;
}
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/common/VRUtil.java b/vrlib/src/main/java/com/asha/vrlib/common/VRUtil.java
index a14d3971..c97d3434 100644
--- a/vrlib/src/main/java/com/asha/vrlib/common/VRUtil.java
+++ b/vrlib/src/main/java/com/asha/vrlib/common/VRUtil.java
@@ -12,6 +12,7 @@
import com.asha.vrlib.model.MDHitPoint;
import com.asha.vrlib.model.MDRay;
import com.asha.vrlib.model.MDVector3D;
+import com.google.vrtoolkit.cardboard.sensors.internal.Vector3d;
/**
* Created by hzqiujiadi on 16/3/13.
@@ -21,7 +22,6 @@ public class VRUtil {
private static final String TAG = "VRUtil";
private static float[] sUIThreadTmp = new float[16];
- private static float[] sGLThreadTmp = new float[16];
private static float[] sTruncatedVector = new float[4];
private static boolean sIsTruncated = false;
@@ -47,13 +47,16 @@ public static void sensorRotationVector2Matrix(SensorEvent event, int rotation,
float[] values = event.values;
switch (rotation){
case Surface.ROTATION_0:
- case Surface.ROTATION_180: /* Notice: not supported for ROTATION_180! */
SensorManager.getRotationMatrixFromVector(output, values);
break;
case Surface.ROTATION_90:
SensorManager.getRotationMatrixFromVector(sUIThreadTmp, values);
SensorManager.remapCoordinateSystem(sUIThreadTmp, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, output);
break;
+ case Surface.ROTATION_180:
+ SensorManager.getRotationMatrixFromVector(sUIThreadTmp, values);
+ SensorManager.remapCoordinateSystem(sUIThreadTmp, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, output);
+ break;
case Surface.ROTATION_270:
SensorManager.getRotationMatrixFromVector(sUIThreadTmp, values);
SensorManager.remapCoordinateSystem(sUIThreadTmp, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, output);
@@ -80,6 +83,24 @@ public static void checkGLThread(String error){
}
}
+ public static void checkNaN(float[] mat) {
+ if (Float.isNaN(mat[0]) || Float.isNaN(mat[1])) {
+ throw new RuntimeException("mat not a number");
+ }
+ }
+
+ public static void checkNaN(double[] mat) {
+ if (Double.isNaN(mat[0]) || Double.isNaN(mat[1])) {
+ throw new RuntimeException("mat not a number");
+ }
+ }
+
+ public static void checkNaN(Vector3d v3d) {
+ if (Double.isNaN(v3d.x) || Double.isNaN(v3d.y) || Double.isNaN(v3d.z)) {
+ throw new RuntimeException("v3d not a number");
+ }
+ }
+
public static void barrelDistortion(double paramA, double paramB, double paramC, PointF src){
double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image
diff --git a/vrlib/src/main/java/com/asha/vrlib/model/MDPinchConfig.java b/vrlib/src/main/java/com/asha/vrlib/model/MDPinchConfig.java
index 58bc135b..cbc3c462 100644
--- a/vrlib/src/main/java/com/asha/vrlib/model/MDPinchConfig.java
+++ b/vrlib/src/main/java/com/asha/vrlib/model/MDPinchConfig.java
@@ -9,7 +9,7 @@ public class MDPinchConfig {
private float max = 5;
private float min = 1;
private float defaultValue = 1;
- private float mSensitivity = 3;
+ private float mSensitivity = 1;
public MDPinchConfig setMax(float max) {
this.max = max;
diff --git a/vrlib/src/main/java/com/asha/vrlib/model/position/MDMutablePosition.java b/vrlib/src/main/java/com/asha/vrlib/model/position/MDMutablePosition.java
index 25358192..2af3bf03 100644
--- a/vrlib/src/main/java/com/asha/vrlib/model/position/MDMutablePosition.java
+++ b/vrlib/src/main/java/com/asha/vrlib/model/position/MDMutablePosition.java
@@ -16,7 +16,7 @@ public class MDMutablePosition extends MDPosition {
private float[] mModelMatrix = null;
private float[] mRotationMatrix = null;
- private static final float[] sSharedTmpMatrix = new float[16];
+ private final float[] mTmpMatrix = new float[16];
private float mX;
private float mY;
@@ -185,8 +185,8 @@ private void ensure(){
// rotation
if (mRotationMatrix != null){
- Matrix.multiplyMM(sSharedTmpMatrix, 0, mRotationMatrix, 0, mModelMatrix, 0);
- System.arraycopy(sSharedTmpMatrix, 0, mModelMatrix, 0, 16);
+ Matrix.multiplyMM(mTmpMatrix, 0, mRotationMatrix, 0, mModelMatrix, 0);
+ System.arraycopy(mTmpMatrix, 0, mModelMatrix, 0, 16);
}
changed = false;
diff --git a/vrlib/src/main/java/com/asha/vrlib/objects/MDCubeMap.java b/vrlib/src/main/java/com/asha/vrlib/objects/MDCubeMap.java
new file mode 100644
index 00000000..d7c5fbcd
--- /dev/null
+++ b/vrlib/src/main/java/com/asha/vrlib/objects/MDCubeMap.java
@@ -0,0 +1,5 @@
+package com.asha.vrlib.objects;
+
+public class MDCubeMap extends MDSphere3D {
+}
+
diff --git a/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsLinePipe.java b/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsLinePipe.java
index de7453f3..307e62fd 100644
--- a/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsLinePipe.java
+++ b/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsLinePipe.java
@@ -12,10 +12,17 @@ public abstract class MDAbsLinePipe {
abstract protected void init(Context context);
private boolean mIsInit;
+ private long mTid;
// MDPosition position = MDPosition.sOriginalPosition;
public final void setup(Context context){
+ long tid = Thread.currentThread().getId();
+ if (mTid != tid) {
+ mTid = tid;
+ mIsInit = false;
+ }
+
if (!mIsInit){
init(context);
mIsInit = true;
diff --git a/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsPlugin.java b/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsPlugin.java
index 2b66003c..d775460f 100644
--- a/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsPlugin.java
+++ b/vrlib/src/main/java/com/asha/vrlib/plugins/MDAbsPlugin.java
@@ -13,9 +13,17 @@ public abstract class MDAbsPlugin {
private boolean mIsInit;
+ private long mTid;
+
private MDPosition mPosition = MDPosition.getOriginalPosition();
public final void setupInGL(Context context){
+ long tid = Thread.currentThread().getId();
+ if (tid != mTid) {
+ mTid = tid;
+ mIsInit = false;
+ }
+
if (!mIsInit){
initInGL(context);
mIsInit = true;
diff --git a/vrlib/src/main/java/com/asha/vrlib/strategy/interactive/MotionStrategy.java b/vrlib/src/main/java/com/asha/vrlib/strategy/interactive/MotionStrategy.java
index 039badeb..30c89ea7 100644
--- a/vrlib/src/main/java/com/asha/vrlib/strategy/interactive/MotionStrategy.java
+++ b/vrlib/src/main/java/com/asha/vrlib/strategy/interactive/MotionStrategy.java
@@ -19,8 +19,8 @@
public class MotionStrategy extends AbsInteractiveStrategy implements SensorEventListener {
private static final String TAG = "MotionStrategy";
-
- private int mDeviceRotation;
+
+ private WindowManager windowManager;
private float[] mSensorMatrix = new float[16];
@@ -55,15 +55,12 @@ public boolean handleDrag(int distanceX, int distanceY) {
@Override
public void onOrientationChanged(Context context) {
- WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- mDeviceRotation = windowManager.getDefaultDisplay().getRotation();
}
@Override
public void turnOnInGL(Context context) {
isOn = true;
- WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- mDeviceRotation = windowManager.getDefaultDisplay().getRotation();
+ windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
for (MD360Director director : getDirectorList()){
director.reset();
}
@@ -129,7 +126,7 @@ public void onSensorChanged(final SensorEvent event) {
switch (type){
case Sensor.TYPE_ROTATION_VECTOR:
// post
- VRUtil.sensorRotationVector2Matrix(event, mDeviceRotation, mSensorMatrix);
+ VRUtil.sensorRotationVector2Matrix(event, windowManager.getDefaultDisplay().getRotation(), mSensorMatrix);
// mTmpMatrix will be used in multi thread.
synchronized (mMatrixLock){
diff --git a/vrlib/src/main/java/com/asha/vrlib/strategy/projection/CubeProjection.java b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/CubeProjection.java
new file mode 100644
index 00000000..b1973c66
--- /dev/null
+++ b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/CubeProjection.java
@@ -0,0 +1,51 @@
+package com.asha.vrlib.strategy.projection;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.asha.vrlib.model.MDMainPluginBuilder;
+import com.asha.vrlib.model.MDPosition;
+import com.asha.vrlib.objects.MDAbsObject3D;
+import com.asha.vrlib.objects.MDCubeMap;
+import com.asha.vrlib.objects.MDObject3DHelper;
+import com.asha.vrlib.plugins.MDAbsPlugin;
+import com.asha.vrlib.plugins.MDPanoramaPlugin;
+
+public class CubeProjection extends AbsProjectionStrategy {
+
+ private MDAbsObject3D object3D;
+
+ public CubeProjection() {
+
+ }
+
+ @Override
+ public MDAbsObject3D getObject3D() {
+ return object3D;
+ }
+
+ @Override
+ public MDPosition getModelPosition() {
+ return MDPosition.getOriginalPosition();
+ }
+
+ @Override
+ public void turnOnInGL(Context context) {
+ object3D = new MDCubeMap();
+ MDObject3DHelper.loadObj(context, object3D);
+ }
+
+ @Override
+ public void turnOffInGL(Context context) {
+ }
+
+ @Override
+ public boolean isSupport(Context context) {
+ return true;
+ }
+
+ @Override
+ public MDAbsPlugin buildMainPlugin(MDMainPluginBuilder builder) {
+ return new MDPanoramaPlugin(builder);
+ }
+}
diff --git a/vrlib/src/main/java/com/asha/vrlib/strategy/projection/PlaneProjection.java b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/PlaneProjection.java
index e04abd30..6639f707 100644
--- a/vrlib/src/main/java/com/asha/vrlib/strategy/projection/PlaneProjection.java
+++ b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/PlaneProjection.java
@@ -215,8 +215,11 @@ public MD360Director createDirector(int index) {
private class OrthogonalDirector extends MD360Director{
+ private final float sNearBase;
+
private OrthogonalDirector(Builder builder) {
super(builder);
+ sNearBase = getNear();
}
@Override
@@ -238,12 +241,13 @@ public void updateSensorMatrix(float[] sensorMatrix) {
protected void updateProjection(){
planeScaleCalculator.setViewportRatio(getRatio());
planeScaleCalculator.calculate();
- final float left = - planeScaleCalculator.getViewportWidth()/2;
- final float right = planeScaleCalculator.getViewportWidth()/2;
- final float bottom = - planeScaleCalculator.getViewportHeight()/2;
- final float top = planeScaleCalculator.getViewportHeight()/2;
+ float scale = sNearBase / getNear();
+ final float left = - planeScaleCalculator.getViewportWidth() / 2 * scale;
+ final float right = planeScaleCalculator.getViewportWidth() / 2 * scale;
+ final float bottom = - planeScaleCalculator.getViewportHeight() / 2 * scale;
+ final float top = planeScaleCalculator.getViewportHeight() / 2 * scale;
final float far = 500;
- Matrix.orthoM(getProjectionMatrix(), 0, left, right, bottom, top, getNear(), far);
+ Matrix.orthoM(getProjectionMatrix(), 0, left, right, bottom, top, 1, far);
}
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/strategy/projection/ProjectionModeManager.java b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/ProjectionModeManager.java
index 69b6f470..8ec91df9 100644
--- a/vrlib/src/main/java/com/asha/vrlib/strategy/projection/ProjectionModeManager.java
+++ b/vrlib/src/main/java/com/asha/vrlib/strategy/projection/ProjectionModeManager.java
@@ -132,6 +132,8 @@ protected AbsProjectionStrategy createStrategy(int mode) {
return new MultiFishEyeProjection(1f, MDDirection.HORIZONTAL);
case MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_VERTICAL:
return new MultiFishEyeProjection(1f, MDDirection.VERTICAL);
+ case MDVRLibrary.PROJECTION_MODE_CUBE:
+ return new CubeProjection();
case MDVRLibrary.PROJECTION_MODE_SPHERE:
default:
return new SphereProjection();
diff --git a/vrlib/src/main/java/com/asha/vrlib/texture/MD360BitmapTexture.java b/vrlib/src/main/java/com/asha/vrlib/texture/MD360BitmapTexture.java
index dce57a9a..cfbbd1e1 100644
--- a/vrlib/src/main/java/com/asha/vrlib/texture/MD360BitmapTexture.java
+++ b/vrlib/src/main/java/com/asha/vrlib/texture/MD360BitmapTexture.java
@@ -85,13 +85,15 @@ private void loadTexture(){
int[] maxSize = new int[1];
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);
+ final AsyncCallback finalCallback = new AsyncCallback(maxSize[0]);
+
// create a new one
- mTmpAsyncCallback = new AsyncCallback(maxSize[0]);
+ mTmpAsyncCallback = finalCallback;
MDMainHandler.sharedHandler().post(new Runnable() {
@Override
public void run() {
- mBitmapProvider.onProvideBitmap(mTmpAsyncCallback);
+ mBitmapProvider.onProvideBitmap(finalCallback);
}
});
}
@@ -136,7 +138,7 @@ private void textureInThread(int textureId, MD360Program program, Bitmap bitmap)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
glCheck("MD360BitmapTexture texImage2D");
- GLES20.glUniform1i(program.getTextureUniformHandle(),0);
+ GLES20.glUniform1i(program.getTextureUniformHandle(), 0);
glCheck("MD360BitmapTexture textureInThread");
}
@@ -151,6 +153,7 @@ public AsyncCallback(int maxSize) {
@Override
public void texture(Bitmap bitmap) {
+ releaseBitmap();
this.bitmapRef = new SoftReference<>(bitmap);
}
diff --git a/vrlib/src/main/java/com/asha/vrlib/texture/MD360CubemapTexture.java b/vrlib/src/main/java/com/asha/vrlib/texture/MD360CubemapTexture.java
new file mode 100644
index 00000000..3856a294
--- /dev/null
+++ b/vrlib/src/main/java/com/asha/vrlib/texture/MD360CubemapTexture.java
@@ -0,0 +1,238 @@
+package com.asha.vrlib.texture;
+
+import android.graphics.Bitmap;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+import com.asha.vrlib.MD360Program;
+import com.asha.vrlib.MDVRLibrary;
+import com.asha.vrlib.common.MDMainHandler;
+
+import java.lang.ref.SoftReference;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.asha.vrlib.common.GLUtil.glCheck;
+import static com.asha.vrlib.common.VRUtil.notNull;
+
+public class MD360CubemapTexture extends MD360Texture {
+
+ private static final String TAG = "MD360CubemapTexture";
+
+ public static final int CUBE_FRONT = 0;
+ public static final int CUBE_BACK = 1;
+ public static final int CUBE_LEFT = 2;
+ public static final int CUBE_RIGHT = 3;
+ public static final int CUBE_TOP = 4;
+ public static final int CUBE_BOTTOM = 5;
+
+ private static final int[] CUBE_TARGETS = new int[] {
+ GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ };
+
+ private MDVRLibrary.ICubemapProvider mCubemapProvider;
+ private boolean mIsReady;
+ private AsyncCallback mTmpAsyncCallback;
+ private AtomicBoolean mTextureDirty = new AtomicBoolean(false);
+ private static final int[] sIsSkybox = new int[]{1};
+
+ private int currentFaceLoading = CUBE_FRONT;
+
+ public MD360CubemapTexture(MDVRLibrary.ICubemapProvider cubemapProvider) {
+ this.mCubemapProvider = cubemapProvider;
+ }
+
+ @Override
+ protected int createTextureId() {
+ final int[] textureHandle = new int[1];
+ GLES20.glGenTextures(1, textureHandle, 0);
+ final int textureId = textureHandle[0];
+
+ // call the provider
+ // to load the bitmap.
+ loadTexture();
+ return textureId;
+ }
+
+ // gl thread
+ @Override
+ public boolean texture(MD360Program program) {
+ if (mTextureDirty.get()){
+ mTextureDirty.set(false);
+ currentFaceLoading = CUBE_FRONT;
+
+ loadTexture();
+
+ mIsReady = false;
+ }
+
+
+ AsyncCallback asyncCallback = mTmpAsyncCallback;
+ int textureId = getCurrentTextureId();
+
+ if (!mIsReady && asyncCallback != null) {
+
+ if (asyncCallback.hasBitmap()){
+ Bitmap bitmap = asyncCallback.getBitmap();
+ Log.d(TAG, "Set texture "+currentFaceLoading);
+
+ textureInThread(textureId, program, bitmap, currentFaceLoading);
+ asyncCallback.releaseBitmap();
+
+ currentFaceLoading++;
+ if(currentFaceLoading < 6)
+ requestBitmap();
+ }
+
+ if(currentFaceLoading >= 6) {
+ mIsReady = true;
+
+ if(mCubemapProvider != null) {
+ MDMainHandler.sharedHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mCubemapProvider.onReady();
+ }
+ });
+ }
+ }
+ }
+
+ if (isReady() && textureId != 0){
+ // Bind texture
+ // Set texture 0 as active texture
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ // Bind the cube map texture to the active opengl texture
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, textureId);
+ // Set shader texture variable to texture 0
+ GLES20.glUniform1i(program.getTextureUniformHandle(), 0);
+ // Set shader isSkybox flag to true
+ GLES20.glUniform1iv(program.getIsSkyboxHandle(), 1, sIsSkybox, 0);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void notifyChanged() {
+ mTextureDirty.set(true);
+ }
+
+ // call from gl thread
+ private void loadTexture(){
+ // release the ref before
+ if (mTmpAsyncCallback != null){
+ mTmpAsyncCallback.releaseBitmap();
+ mTmpAsyncCallback = null;
+ }
+
+ // get texture max size.
+ int[] maxSize = new int[1];
+ GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);
+
+ // create a new one
+ mTmpAsyncCallback = new AsyncCallback(maxSize[0]);
+
+ requestBitmap();
+ }
+
+ private void requestBitmap() {
+ MDMainHandler.sharedHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mCubemapProvider.onProvideCubemap(mTmpAsyncCallback, currentFaceLoading);
+ }
+ });
+ }
+
+ @Override
+ public boolean isReady() {
+ return mIsReady;
+ }
+
+ @Override
+ public void destroy() {
+ // release the ref before
+ if (mTmpAsyncCallback != null){
+ mTmpAsyncCallback.releaseBitmap();
+ mTmpAsyncCallback = null;
+ }
+ }
+
+ @Override
+ public void release() {
+ }
+
+ private void textureInThread(int textureId, MD360Program program, Bitmap bitmap, int face) {
+ notNull(bitmap, "bitmap can't be null!");
+
+ if (isEmpty(textureId)) return;
+
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ glCheck("MD360BitmapTexture glActiveTexture");
+
+ // Bind to the texture in OpenGL
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, textureId);
+ glCheck("MD360BitmapTexture glBindTexture");
+
+ // Set filtering
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+
+ // Load the bitmap into the bound texture.
+ GLUtils.texImage2D(CUBE_TARGETS[face], 0, bitmap, 0);
+ glCheck("MD360BitmapTexture texImage2D");
+
+ // Set shader texture variable to texture 0
+ GLES20.glUniform1i(program.getTextureUniformHandle(), 0);
+ glCheck("MD360BitmapTexture textureInThread");
+ }
+
+ // @todo this can be refactored as its repeated in @MD360BitmapTexture
+ private static class AsyncCallback implements Callback {
+ private SoftReference bitmapRef;
+
+ private int maxSize;
+
+ public AsyncCallback(int maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ @Override
+ public void texture(Bitmap bitmap) {
+ this.bitmapRef = new SoftReference<>(bitmap);
+ }
+
+ @Override
+ public int getMaxTextureSize() {
+ return maxSize;
+ }
+
+ public Bitmap getBitmap(){
+ return bitmapRef != null ? bitmapRef.get() : null;
+ }
+
+ public boolean hasBitmap(){
+ return bitmapRef != null && bitmapRef.get() != null;
+ }
+
+ public void releaseBitmap(){
+ if(bitmapRef != null) {
+ bitmapRef.clear();
+ bitmapRef = null;
+ }
+ }
+ }
+
+ public interface Callback {
+ void texture(Bitmap bitmap);
+ int getMaxTextureSize();
+ }
+}
diff --git a/vrlib/src/main/java/com/google/android/apps/muzei/render/GLTextureView.java b/vrlib/src/main/java/com/google/android/apps/muzei/render/GLTextureView.java
index fd2b3ea3..7751e218 100644
--- a/vrlib/src/main/java/com/google/android/apps/muzei/render/GLTextureView.java
+++ b/vrlib/src/main/java/com/google/android/apps/muzei/render/GLTextureView.java
@@ -464,13 +464,21 @@ protected void onAttachedToWindow() {
}
if (mDetached && (mRenderer != null)) {
int renderMode = RENDERMODE_CONTINUOUSLY;
+ int w = 0, h = 0;
+
if (mGLThread != null) {
renderMode = mGLThread.getRenderMode();
+ w = mGLThread.mWidth;
+ h = mGLThread.mHeight;
}
mGLThread = new GLThread(mThisWeakRef);
if (renderMode != RENDERMODE_CONTINUOUSLY) {
mGLThread.setRenderMode(renderMode);
}
+ if (w != 0 && h != 0) {
+ mGLThread.mWidth = w;
+ mGLThread.mHeight = h;
+ }
mGLThread.start();
}
mDetached = false;
@@ -484,7 +492,7 @@ protected void onAttachedToWindow() {
@Override
protected void onDetachedFromWindow() {
if (LOG_ATTACH_DETACH) {
- Log.d(TAG, "onDetachedFromWindow");
+ Log.d(TAG, "onDetachedFromWindow:" + mGLThread);
}
if (mGLThread != null) {
mGLThread.requestExitAndWait();
@@ -1063,6 +1071,21 @@ private void guardedRun() throws InterruptedException {
while (true) {
synchronized (sGLThreadManager) {
while (true) {
+ if (LOG_RENDERER_DRAW_FRAME) {
+ Log.v(TAG, "guardedRun run, tid=" + getId()
+ + " mHaveEglContext: " + mHaveEglContext
+ + " mHaveEglSurface: " + mHaveEglSurface
+ + " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface
+ + " mPaused: " + mPaused
+ + " mHasSurface: " + mHasSurface
+ + " mSurfaceIsBad: " + mSurfaceIsBad
+ + " mWaitingForSurface: " + mWaitingForSurface
+ + " mWidth: " + mWidth
+ + " mHeight: " + mHeight
+ + " mRequestRender: " + mRequestRender
+ + " mRenderMode: " + mRenderMode);
+ }
+
if (mShouldExit) {
return;
}
@@ -1335,6 +1358,8 @@ private void guardedRun() throws InterruptedException {
stopEglSurfaceLocked();
stopEglContextLocked();
}
+
+ Log.e(TAG, "guardedRun exit:" + Thread.currentThread());
}
}
@@ -1451,6 +1476,7 @@ public void onResume() {
}
public void onWindowResize(int w, int h) {
+ Log.d(TAG, "onWindowResize:" + w + "," + h);
synchronized (sGLThreadManager) {
mWidth = w;
mHeight = h;
diff --git a/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/OrientationEKF.java b/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/OrientationEKF.java
index 3d187efa..cb82df55 100644
--- a/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/OrientationEKF.java
+++ b/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/OrientationEKF.java
@@ -64,6 +64,7 @@ public class OrientationEKF {
private Matrix3x3d magObservationFunctionForNumericalJacobianTempM = new Matrix3x3d();
private boolean alignedToGravity;
private boolean alignedToNorth;
+ private So3Helper so3Helper = new So3Helper();
public OrientationEKF() {
this.reset();
@@ -247,7 +248,7 @@ public synchronized void processAcc(Vector3d acc, long sensorTimeStamp) {
Matrix3x3d.mult(this.so3LastMotion, this.so3SensorFromWorld, this.so3SensorFromWorld);
this.updateCovariancesAfterMotion();
} else {
- So3Util.sO3FromTwoVec(this.down, this.mz, this.so3SensorFromWorld);
+ so3Helper.sO3FromTwoVec(this.down, this.mz, this.so3SensorFromWorld);
this.alignedToGravity = true;
}
@@ -351,13 +352,13 @@ private void updateCovariancesAfterMotion() {
private void accObservationFunctionForNumericalJacobian(Matrix3x3d so3SensorFromWorldPred, Vector3d result) {
Matrix3x3d.mult(so3SensorFromWorldPred, this.down, this.mh);
- So3Util.sO3FromTwoVec(this.mh, this.mz, this.accObservationFunctionForNumericalJacobianTempM);
- So3Util.muFromSO3(this.accObservationFunctionForNumericalJacobianTempM, result);
+ so3Helper.sO3FromTwoVec(this.mh, this.mz, this.accObservationFunctionForNumericalJacobianTempM);
+ so3Helper.muFromSO3(this.accObservationFunctionForNumericalJacobianTempM, result);
}
private void magObservationFunctionForNumericalJacobian(Matrix3x3d so3SensorFromWorldPred, Vector3d result) {
Matrix3x3d.mult(so3SensorFromWorldPred, this.north, this.mh);
- So3Util.sO3FromTwoVec(this.mh, this.mz, this.magObservationFunctionForNumericalJacobianTempM);
- So3Util.muFromSO3(this.magObservationFunctionForNumericalJacobianTempM, result);
+ so3Helper.sO3FromTwoVec(this.mh, this.mz, this.magObservationFunctionForNumericalJacobianTempM);
+ so3Helper.muFromSO3(this.magObservationFunctionForNumericalJacobianTempM, result);
}
}
diff --git a/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/So3Helper.java b/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/So3Helper.java
new file mode 100644
index 00000000..43754563
--- /dev/null
+++ b/vrlib/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/So3Helper.java
@@ -0,0 +1,127 @@
+package com.google.vrtoolkit.cardboard.sensors.internal;
+
+public class So3Helper {
+ private static final double M_SQRT1_2 = 0.7071067811865476;
+ private static final double ONE_6TH = 0.1666666716337204;
+ private static final double ONE_20TH = 0.1666666716337204;
+ private Vector3d temp31;
+ private Vector3d sO3FromTwoVecN;
+ private Vector3d sO3FromTwoVecA;
+ private Vector3d sO3FromTwoVecB;
+ private Vector3d sO3FromTwoVecRotationAxis;
+ private Matrix3x3d sO3FromTwoVec33R1;
+ private Matrix3x3d sO3FromTwoVec33R2;
+ private Vector3d muFromSO3R2;
+ private Vector3d rotationPiAboutAxisTemp;
+
+ public So3Helper() {
+ temp31 = new Vector3d();
+ sO3FromTwoVecN = new Vector3d();
+ sO3FromTwoVecA = new Vector3d();
+ sO3FromTwoVecB = new Vector3d();
+ sO3FromTwoVecRotationAxis = new Vector3d();
+ sO3FromTwoVec33R1 = new Matrix3x3d();
+ sO3FromTwoVec33R2 = new Matrix3x3d();
+ muFromSO3R2 = new Vector3d();
+ rotationPiAboutAxisTemp = new Vector3d();
+ }
+
+ public void sO3FromTwoVec(final Vector3d a, final Vector3d b, final Matrix3x3d result) {
+ Vector3d.cross(a, b, sO3FromTwoVecN);
+ if (sO3FromTwoVecN.length() == 0.0) {
+ final double dot = Vector3d.dot(a, b);
+ if (dot >= 0.0) {
+ result.setIdentity();
+ }
+ else {
+ Vector3d.ortho(a, sO3FromTwoVecRotationAxis);
+ rotationPiAboutAxis(sO3FromTwoVecRotationAxis, result);
+ }
+ return;
+ }
+ sO3FromTwoVecA.set(a);
+ sO3FromTwoVecB.set(b);
+ sO3FromTwoVecN.normalize();
+ sO3FromTwoVecA.normalize();
+ sO3FromTwoVecB.normalize();
+ final Matrix3x3d r1 = sO3FromTwoVec33R1;
+ r1.setColumn(0, sO3FromTwoVecA);
+ r1.setColumn(1, sO3FromTwoVecN);
+ Vector3d.cross(sO3FromTwoVecN, sO3FromTwoVecA, temp31);
+ r1.setColumn(2, temp31);
+ final Matrix3x3d r2 = sO3FromTwoVec33R2;
+ r2.setColumn(0, sO3FromTwoVecB);
+ r2.setColumn(1, sO3FromTwoVecN);
+ Vector3d.cross(sO3FromTwoVecN, sO3FromTwoVecB, temp31);
+ r2.setColumn(2, temp31);
+ r1.transpose();
+ Matrix3x3d.mult(r2, r1, result);
+ }
+
+ private void rotationPiAboutAxis(final Vector3d v, final Matrix3x3d result) {
+ rotationPiAboutAxisTemp.set(v);
+ rotationPiAboutAxisTemp.scale(3.141592653589793 / rotationPiAboutAxisTemp.length());
+ final double invTheta = 0.3183098861837907;
+ final double kA = 0.0;
+ final double kB = 0.20264236728467558;
+ rodriguesSo3Exp(rotationPiAboutAxisTemp, kA, kB, result);
+ }
+
+ public void muFromSO3(final Matrix3x3d so3, final Vector3d result) {
+ final double cosAngle = (so3.get(0, 0) + so3.get(1, 1) + so3.get(2, 2) - 1.0) * 0.5;
+ result.set((so3.get(2, 1) - so3.get(1, 2)) / 2.0, (so3.get(0, 2) - so3.get(2, 0)) / 2.0, (so3.get(1, 0) - so3.get(0, 1)) / 2.0);
+ final double sinAngleAbs = result.length();
+ if (cosAngle > 0.7071067811865476) {
+ if (sinAngleAbs > 0.0) {
+ result.scale(Math.asin(sinAngleAbs) / sinAngleAbs);
+ }
+ }
+ else if (cosAngle > -0.7071067811865476) {
+ final double angle = Math.acos(cosAngle);
+ result.scale(angle / sinAngleAbs);
+ }
+ else {
+ final double angle = 3.141592653589793 - Math.asin(sinAngleAbs);
+ final double d0 = so3.get(0, 0) - cosAngle;
+ final double d = so3.get(1, 1) - cosAngle;
+ final double d2 = so3.get(2, 2) - cosAngle;
+ final Vector3d r2 = muFromSO3R2;
+ if (d0 * d0 > d * d && d0 * d0 > d2 * d2) {
+ r2.set(d0, (so3.get(1, 0) + so3.get(0, 1)) / 2.0, (so3.get(0, 2) + so3.get(2, 0)) / 2.0);
+ }
+ else if (d * d > d2 * d2) {
+ r2.set((so3.get(1, 0) + so3.get(0, 1)) / 2.0, d, (so3.get(2, 1) + so3.get(1, 2)) / 2.0);
+ }
+ else {
+ r2.set((so3.get(0, 2) + so3.get(2, 0)) / 2.0, (so3.get(2, 1) + so3.get(1, 2)) / 2.0, d2);
+ }
+ if (Vector3d.dot(r2, result) < 0.0) {
+ r2.scale(-1.0);
+ }
+ r2.normalize();
+ r2.scale(angle);
+ result.set(r2);
+ }
+ }
+
+ private static void rodriguesSo3Exp(final Vector3d w, final double kA, final double kB, final Matrix3x3d result) {
+ final double wx2 = w.x * w.x;
+ final double wy2 = w.y * w.y;
+ final double wz2 = w.z * w.z;
+ result.set(0, 0, 1.0 - kB * (wy2 + wz2));
+ result.set(1, 1, 1.0 - kB * (wx2 + wz2));
+ result.set(2, 2, 1.0 - kB * (wx2 + wy2));
+ double a = kA * w.z;
+ double b = kB * (w.x * w.y);
+ result.set(0, 1, b - a);
+ result.set(1, 0, b + a);
+ a = kA * w.y;
+ b = kB * (w.x * w.z);
+ result.set(0, 2, b + a);
+ result.set(2, 0, b - a);
+ a = kA * w.x;
+ b = kB * (w.y * w.z);
+ result.set(1, 2, b - a);
+ result.set(2, 1, b + a);
+ }
+}
diff --git a/vrlib/src/main/res/raw/per_pixel_fragment_shader_cubemap.glsl b/vrlib/src/main/res/raw/per_pixel_fragment_shader_cubemap.glsl
new file mode 100644
index 00000000..37bf84fb
--- /dev/null
+++ b/vrlib/src/main/res/raw/per_pixel_fragment_shader_cubemap.glsl
@@ -0,0 +1,16 @@
+precision mediump float;
+
+varying vec3 v_Position; // Direction vector representing a 3D texture coordinate
+uniform samplerCube u_Texture; // Cubemap texture sampler
+
+vec3 m_TmpCoordinate;
+
+void main()
+{
+ // Mirror image to be shown correctly
+ m_TmpCoordinate[0] = 1. - v_Position[0];
+ m_TmpCoordinate[1] = v_Position[1];
+ m_TmpCoordinate[2] = v_Position[2];
+
+ gl_FragColor = textureCube(u_Texture, m_TmpCoordinate);
+}
\ No newline at end of file
diff --git a/vrlib/src/main/res/raw/per_pixel_vertex_shader.glsl b/vrlib/src/main/res/raw/per_pixel_vertex_shader.glsl
index 6f7849ab..96d72dc0 100644
--- a/vrlib/src/main/res/raw/per_pixel_vertex_shader.glsl
+++ b/vrlib/src/main/res/raw/per_pixel_vertex_shader.glsl
@@ -2,6 +2,7 @@ uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/pr
uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix.
uniform mat4 u_STMatrix;
uniform bool u_UseSTM;
+uniform bool u_IsSkybox;
attribute vec4 a_Position; // Per-vertex position information we will pass in.
//attribute vec4 a_Color; // Per-vertex color information we will pass in.
@@ -16,8 +17,13 @@ varying vec2 v_TexCoordinate; // This will be passed into the fragment shader.
// The entry point for our vertex shader.
void main()
{
- // Transform the vertex into eye space.
- v_Position = vec3(u_MVMatrix * a_Position);
+ // Transform the vertex into eye space.
+ if(!u_IsSkybox) {
+ v_Position = vec3(u_MVMatrix * a_Position);
+ } else {
+ // When using cubemap, coordinates are the same as the position
+ v_Position = vec3(a_Position);
+ }
// Pass through the color.
//v_Color = a_Color;