package org.wheelmap.android.tango.renderer; import android.content.Context; import android.graphics.Bitmap; import android.util.Log; import android.view.MotionEvent; import com.google.atap.tangoservice.TangoPoseData; import com.projecttango.tangosupport.TangoSupport; import org.rajawali3d.lights.DirectionalLight; import org.rajawali3d.materials.Material; import org.rajawali3d.materials.textures.ATexture; import org.rajawali3d.materials.textures.StreamingTexture; import org.rajawali3d.math.Matrix4; import org.rajawali3d.math.Quaternion; import org.rajawali3d.primitives.ScreenQuad; import org.rajawali3d.renderer.Renderer; import javax.microedition.khronos.opengles.GL10; public abstract class TangoRajawaliRenderer extends Renderer { private static final String TAG = "TangoRajawaliRenderer"; private float[] textureCoords0 = new float[]{0.0F, 1.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F, 0.0F}; public interface ScreenshotCaptureListener { void onScreenshotCaptured(Bitmap bitmap); } // Augmented Reality related fields private ScreenQuad backgroundQuad; private ATexture mTangoCameraTexture; private boolean mSceneCameraConfigured; private WheelmapTangoRajawaliRenderer.ScreenshotCaptureListener screenshotCaptureListener = null; TangoRajawaliRenderer(Context context) { super(context); } @Override protected void initScene() { // Create a quad covering the whole background and assign a texture to it where the // Tango color camera contents will be rendered. // Create a quad covering the whole background and assign a texture to it where the // Tango color camera contents will be rendered. if (backgroundQuad == null) { backgroundQuad = new ScreenQuad(); backgroundQuad.getGeometry().setTextureCoords(textureCoords0); } Material tangoCameraMaterial = new Material(); tangoCameraMaterial.setColorInfluence(0); // We need to use Rajawali's {@code StreamingTexture} since it sets up the texture // for GL_TEXTURE_EXTERNAL_OES rendering mTangoCameraTexture = new StreamingTexture("camera", (StreamingTexture.ISurfaceListener) null); try { tangoCameraMaterial.addTexture(mTangoCameraTexture); backgroundQuad.setMaterial(tangoCameraMaterial); } catch (ATexture.TextureException e) { Log.e(TAG, "Exception creating texture for RGB camera contents", e); } getCurrentScene().addChildAt(backgroundQuad, 0); // Add a directional light in an arbitrary direction. DirectionalLight light = new DirectionalLight(1, 0.2, -1); light.setColor(1, 1, 1); light.setPower(0.8f); light.setPosition(3, 2, 4); getCurrentScene().addLight(light); } /** * Update background texture's UV coordinates when device orientation is changed (i.e., change * between landscape and portrait mode. * This must be run in the OpenGL thread. */ public void updateColorCameraTextureUvGlThread(int rotation) { Log.d(TAG, "updateColorCameraTextureUvGlThread() called with " + "rotation = [" + rotation + "]"); if (backgroundQuad == null) { backgroundQuad = new ScreenQuad(); } float[] textureCoords = TangoSupport.getVideoOverlayUVBasedOnDisplayRotation(textureCoords0, rotation); backgroundQuad.getGeometry().setTextureCoords(textureCoords, true); backgroundQuad.getGeometry().reload(); } /** * It returns the ID currently assigned to the texture where the Tango color camera contents * should be rendered. * NOTE: This must be called from the OpenGL render thread - it is not thread safe. */ public int getTextureId() { return mTangoCameraTexture == null ? -1 : mTangoCameraTexture.getTextureId(); } /** * We need to override this method to mark the camera for re-configuration (set proper * projection matrix) since it will be reset by Rajawali on surface changes. */ @Override public void onRenderSurfaceSizeChanged(GL10 gl, int width, int height) { super.onRenderSurfaceSizeChanged(gl, width, height); mSceneCameraConfigured = false; } public boolean isSceneCameraConfigured() { return mSceneCameraConfigured; } /** * Update the scene camera based on the provided pose in Tango start of service frame. * The camera pose should match the pose of the camera color at the time of the last rendered * RGB frame, which can be retrieved with this.getTimestamp(); * <p/> * NOTE: This must be called from the OpenGL render thread; it is not thread safe. */ public void updateRenderCameraPose(TangoPoseData cameraPose) { float[] rotation = cameraPose.getRotationAsFloats(); float[] translation = cameraPose.getTranslationAsFloats(); Quaternion quaternion = new Quaternion(rotation[3], rotation[0], rotation[1], rotation[2]); // Conjugating the Quaternion is needed because Rajawali uses left-handed convention for // quaternions. getCurrentCamera().setRotation(quaternion.conjugate()); getCurrentCamera().setPosition(translation[0], translation[1], translation[2]); } /** * Sets the projection matrix for the scene camera to match the parameters of the color camera, * provided by the {@code TangoCameraIntrinsics}. */ public void setProjectionMatrix(float[] matrix) { Log.d(TAG, "setProjectionMatrix"); getCurrentCamera().setProjectionMatrix(new Matrix4(matrix)); mSceneCameraConfigured = true; } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { } @Override public void onTouchEvent(MotionEvent event) { } @Override public void onRenderFrame(GL10 gl) { super.onRenderFrame(gl); if (screenshotCaptureListener != null) { Bitmap bitmap = ScreenshotHelper.getBitmap(0, 0, getDefaultViewportWidth(), getDefaultViewportHeight(), gl); screenshotCaptureListener.onScreenshotCaptured(bitmap); screenshotCaptureListener = null; } } public void captureScreenshot(ScreenshotCaptureListener listener) { this.screenshotCaptureListener = listener; } }