1274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen/*
2274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * Copyright (C) 2011 The Android Open Source Project
3274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen *
4274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License");
5274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * you may not use this file except in compliance with the License.
6274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * You may obtain a copy of the License at
7274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen *
8274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen *      http://www.apache.org/licenses/LICENSE-2.0
9274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen *
10274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * Unless required by applicable law or agreed to in writing, software
11274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS,
12274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * See the License for the specific language governing permissions and
14274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen * limitations under the License.
15274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen */
16274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen
17274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include <GLES2/gl2.h>
18274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include <GLES2/gl2ext.h>
19eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal#include <jni.h>
20274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include <math.h>
21274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include <stdio.h>
22274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include <stdlib.h>
23274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include "db_utilities_camera.h"
24eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal#include "mosaic/ImageUtils.h"
25eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal#include "mosaic_renderer/FrameBuffer.h"
26eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal#include "mosaic_renderer/WarpRenderer.h"
2741a2e9735136f372de95652d0828600282c8e967mbansal#include "mosaic_renderer/SurfaceTextureRenderer.h"
281e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal#include "mosaic_renderer/YVURenderer.h"
29eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
30274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include "mosaic/Log.h"
31274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#define LOG_TAG "MosaicRenderer"
32eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
33274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include "mosaic_renderer_jni.h"
34eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
35eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// Texture handle
3641a2e9735136f372de95652d0828600282c8e967mbansalGLuint gSurfaceTextureID[1];
37eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
3841a2e9735136f372de95652d0828600282c8e967mbansalbool gWarpImage = true;
39eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
401e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Low-Res input image frame in YUVA format for preview rendering and processing
411e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// and high-res YUVA input image for processing.
421e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalunsigned char* gPreviewImage[NR];
4341a2e9735136f372de95652d0828600282c8e967mbansal// Low-Res & high-res preview image width
441e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalint gPreviewImageWidth[NR];
4541a2e9735136f372de95652d0828600282c8e967mbansal// Low-Res & high-res preview image height
461e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalint gPreviewImageHeight[NR];
47eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
481e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Semaphore to protect simultaneous read/writes from gPreviewImage
491e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalsem_t gPreviewImage_semaphore;
50eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
51eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// Off-screen preview FBO width (large enough to store the entire
52445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li// preview mosaic). FBO is frame buffer object.
53eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalint gPreviewFBOWidth;
54eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// Off-screen preview FBO height (large enough to store the entire
55eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// preview mosaic).
56eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalint gPreviewFBOHeight;
57eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
58a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// gK is the transformation to map the canonical {-1,1} vertex coordinate system
59a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// to the {0,gPreviewImageWidth[LR]} input image frame coordinate system before
60a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// applying the given affine transformation trs. gKm is the corresponding
61a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// transformation for going to the {0,gPreviewFBOWidth}.
62a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gK[9];
63a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gKinv[9];
64a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gKm[9];
65a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gKminv[9];
66a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
6741a2e9735136f372de95652d0828600282c8e967mbansal// Shader to copy input SurfaceTexture into and RGBA FBO. The two shaders
6841a2e9735136f372de95652d0828600282c8e967mbansal// render to the textures with dimensions corresponding to the low-res and
6941a2e9735136f372de95652d0828600282c8e967mbansal// high-res image frames.
7041a2e9735136f372de95652d0828600282c8e967mbansalSurfaceTextureRenderer gSurfTexRenderer[NR];
7141a2e9735136f372de95652d0828600282c8e967mbansal// Off-screen FBOs to store the low-res and high-res RGBA copied out from
7241a2e9735136f372de95652d0828600282c8e967mbansal// the SurfaceTexture by the gSurfTexRenderers.
7341a2e9735136f372de95652d0828600282c8e967mbansalFrameBuffer gBufferInput[NR];
741e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
751e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Shader to convert RGBA textures into YVU textures for processing
761e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalYVURenderer gYVURenderer[NR];
771e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Off-screen FBOs to store the low-res and high-res YVU textures for processing
781e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalFrameBuffer gBufferInputYVU[NR];
791e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
8047f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen// Shader to translate the flip-flop FBO - gBuffer[1-current] -> gBuffer[current]
811e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalWarpRenderer gWarper1;
8247f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen// Shader to add warped current frame to the flip-flop FBO - gBuffer[current]
831e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalWarpRenderer gWarper2;
841e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Off-screen FBOs (flip-flop) to store the result of gWarper1 & gWarper2
851e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalFrameBuffer gBuffer[2];
861e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
87eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// Shader to warp and render the preview FBO to the screen
88eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalWarpRenderer gPreview;
891e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
901e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Index of the gBuffer FBO gWarper1 is going to write into
911e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalint gCurrentFBOIndex = 0;
921e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
93a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// 3x3 Matrices holding the transformation of this frame (gThisH1t) and of
94a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// the last frame (gLastH1t) w.r.t the first frame.
95a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gThisH1t[9];
96a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gLastH1t[9];
97a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
98a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// Variables to represent the fixed position of the top-left corner of the
99a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// current frame in the previewFBO
100a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gCenterOffsetX = 0.0f;
101a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gCenterOffsetY = 0.0f;
102a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
103a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// X-Offset of the viewfinder (current frame) w.r.t
104a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// (gCenterOffsetX, gCenterOffsetY). This offset varies with time and is
105a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// used to pan the viewfinder across the UI layout.
106a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gPanOffset = 0.0f;
1071e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
1081e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// Variables tracking the translation value for the current frame and the
1091e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// last frame (both w.r.t the first frame). The difference between these
1101e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// values is used to control the panning speed of the viewfinder display
1111e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// on the UI screen.
1121e762b1f935c9d4a06af6dd56121590ca81d48b1mbansaldouble gThisTx = 0.0f;
1131e762b1f935c9d4a06af6dd56121590ca81d48b1mbansaldouble gLastTx = 0.0f;
114eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
115a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// These are the scale factors used by the gPreview shader to ensure that
116a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// the image frame is correctly scaled to the full UI layout height while
117a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// maintaining its aspect ratio
118a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gUILayoutScalingX = 1.0f;
119a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble gUILayoutScalingY = 1.0f;
120a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
121d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen// Whether the view that we will render preview FBO onto is in landscape or portrait
122d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen// orientation.
123d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chenbool gIsLandscapeOrientation = true;
124d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
125a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// State of the viewfinder. Set to false when the viewfinder hits the UI edge.
126a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansalbool gPanViewfinder = true;
127a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
128eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// Affine transformation in GL 4x4 format (column-major) to warp the
129a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// last frame mosaic into the current frame coordinate system.
130eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalGLfloat g_dAffinetransGL[16];
131a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble g_dAffinetrans[16];
132eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
133a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// Affine transformation in GL 4x4 format (column-major) to translate the
134a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// preview FBO across the screen (viewfinder panning).
135a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansalGLfloat g_dAffinetransPanGL[16];
136a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble g_dAffinetransPan[16];
137eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
138a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// XY translation in GL 4x4 format (column-major) to center the current
139a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// preview mosaic in the preview FBO
140a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansalGLfloat g_dTranslationToFBOCenterGL[16];
141a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansaldouble g_dTranslationToFBOCenter[16];
1421e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
143eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// GL 4x4 Identity transformation
144d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta ChenGLfloat g_dAffinetransIdentGL[] = {
145eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    1., 0., 0., 0.,
146eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    0., 1., 0., 0.,
147eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    0., 0., 1., 0.,
148eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    0., 0., 0., 1.};
149eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
150d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen// GL 4x4 Rotation transformation (column-majored): 90 degree
151d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta ChenGLfloat g_dAffinetransRotation90GL[] = {
152d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    0., 1., 0., 0.,
153d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    -1., 0., 0., 0.,
154d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    0., 0., 1., 0.,
155d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    0., 0., 0., 1.};
156d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
157d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen// 3x3 Rotation transformation (row-majored): 90 degree
158d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chendouble gRotation90[] = {
159d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    0., -1., 0.,
160d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    1., 0., 0.,
161d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    0., 0., 1.,};
162d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
163d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
1641e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalfloat g_dIdent3x3[] = {
1651e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    1.0, 0.0, 0.0,
1661e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    0.0, 1.0, 0.0,
1671e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    0.0, 0.0, 1.0};
1681e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
16941a2e9735136f372de95652d0828600282c8e967mbansalconst int GL_TEXTURE_EXTERNAL_OES_ENUM = 0x8D65;
170eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
171eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalstatic void printGLString(const char *name, GLenum s) {
172eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    const char *v = (const char *) glGetString(s);
173274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen    LOGI("GL %s = %s", name, v);
174eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
175eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
1764fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kongvoid checkFramebufferStatus(const char* name) {
1774fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1784fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    if (status == 0) {
1794fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong      LOGE("Checking completeness of Framebuffer:%s", name);
1804fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong      checkGlError("checkFramebufferStatus (is the target \"GL_FRAMEBUFFER\"?)");
1814fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    } else if (status != GL_FRAMEBUFFER_COMPLETE) {
1824fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        const char* msg = "not listed";
1834fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        switch (status) {
1844fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong          case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: msg = "attachment"; break;
1854fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong          case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: msg = "dimensions"; break;
1864fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong          case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: msg = "missing attachment"; break;
1874fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong          case GL_FRAMEBUFFER_UNSUPPORTED: msg = "unsupported"; break;
1884fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        }
1894fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        LOGE("Framebuffer: %s is INCOMPLETE: %s, %x", name, msg, status);
1904fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    }
1914fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong}
1924fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong
193eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal// @return false if there was an error
1944fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kongbool checkGLErrorDetail(const char* file, int line, const char* op) {
195eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    GLint error = glGetError();
1964fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    const char* err_msg = "NOT_LISTED";
197eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    if (error != 0) {
1984fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        switch (error) {
1994fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong            case GL_INVALID_VALUE: err_msg = "NOT_LISTED_YET"; break;
2004fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong            case GL_INVALID_OPERATION: err_msg = "INVALID_OPERATION"; break;
2014fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong            case GL_INVALID_ENUM: err_msg = "INVALID_ENUM"; break;
2024fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        }
2034fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong        LOGE("Error after %s(). glError: %s (0x%x) in line %d of %s", op, err_msg, error, line, file);
204eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        return false;
205eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    }
206eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    return true;
207eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
208eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
20941a2e9735136f372de95652d0828600282c8e967mbansalvoid bindSurfaceTexture(GLuint texId)
210eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
21141a2e9735136f372de95652d0828600282c8e967mbansal    glBindTexture(GL_TEXTURE_EXTERNAL_OES_ENUM, texId);
21241a2e9735136f372de95652d0828600282c8e967mbansal
21341a2e9735136f372de95652d0828600282c8e967mbansal    // Can't do mipmapping with camera source
21441a2e9735136f372de95652d0828600282c8e967mbansal    glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MIN_FILTER,
21541a2e9735136f372de95652d0828600282c8e967mbansal            GL_LINEAR);
21641a2e9735136f372de95652d0828600282c8e967mbansal    glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MAG_FILTER,
21741a2e9735136f372de95652d0828600282c8e967mbansal            GL_LINEAR);
21841a2e9735136f372de95652d0828600282c8e967mbansal    // Clamp to edge is the only option
21941a2e9735136f372de95652d0828600282c8e967mbansal    glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_S,
22041a2e9735136f372de95652d0828600282c8e967mbansal            GL_CLAMP_TO_EDGE);
22141a2e9735136f372de95652d0828600282c8e967mbansal    glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_T,
22241a2e9735136f372de95652d0828600282c8e967mbansal            GL_CLAMP_TO_EDGE);
223eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
224eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
2251e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalvoid ClearPreviewImage(int mID)
226eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
2271e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    unsigned char* ptr = gPreviewImage[mID];
22841a2e9735136f372de95652d0828600282c8e967mbansal    for(int j = 0, i = 0;
2291e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            j < gPreviewImageWidth[mID] * gPreviewImageHeight[mID] * 4;
23041a2e9735136f372de95652d0828600282c8e967mbansal            j += 4)
23141a2e9735136f372de95652d0828600282c8e967mbansal    {
23241a2e9735136f372de95652d0828600282c8e967mbansal            ptr[i++] = 0;
23341a2e9735136f372de95652d0828600282c8e967mbansal            ptr[i++] = 0;
23441a2e9735136f372de95652d0828600282c8e967mbansal            ptr[i++] = 0;
23541a2e9735136f372de95652d0828600282c8e967mbansal            ptr[i++] = 255;
23641a2e9735136f372de95652d0828600282c8e967mbansal    }
23741a2e9735136f372de95652d0828600282c8e967mbansal
238eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
239eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
240eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalvoid ConvertAffine3x3toGL4x4(double *matGL44, double *mat33)
241eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
242eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[0] = mat33[0];
243eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[1] = mat33[3];
244eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[2] = 0.0;
245eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[3] = mat33[6];
246eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
247eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[4] = mat33[1];
248eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[5] = mat33[4];
249eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[6] = 0.0;
250eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[7] = mat33[7];
251eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
252eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[8] = 0;
253eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[9] = 0;
254eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[10] = 1.0;
255eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[11] = 0.0;
256eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
257eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[12] = mat33[2];
258eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[13] = mat33[5];
259eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[14] = 0.0;
260eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    matGL44[15] = mat33[8];
261eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
262eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
263d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chenbool continuePanningFBO(double panOffset) {
264d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    double normalizedScreenLimitLeft = -1.0 + VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
265d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    double normalizedScreenLimitRight = 1.0 - VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
266d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    double normalizedXPositionOnScreenLeft;
267d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    double normalizedXPositionOnScreenRight;
268d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
269d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    // Compute the position of the current frame in the screen coordinate system
270d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    if (gIsLandscapeOrientation) {
271d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        normalizedXPositionOnScreenLeft = (2.0 *
272d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
273d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gUILayoutScalingX;
274d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        normalizedXPositionOnScreenRight = (2.0 *
275d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
276d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gPreviewFBOWidth - 1.0) * gUILayoutScalingX;
277d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    } else {
278d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        normalizedXPositionOnScreenLeft = (2.0 *
279d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
280d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gUILayoutScalingY;
281d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        normalizedXPositionOnScreenRight = (2.0 *
282d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
283d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gPreviewFBOWidth - 1.0) * gUILayoutScalingY;
284d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    }
285d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
286d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    // Stop the viewfinder panning if we hit the maximum border allowed for
287d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    // this UI layout
288d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    if (normalizedXPositionOnScreenRight > normalizedScreenLimitRight ||
289d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            normalizedXPositionOnScreenLeft < normalizedScreenLimitLeft) {
290d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        return false;
291d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    } else {
292d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        return true;
293d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    }
294d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen}
295d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
2961e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// This function computes fills the 4x4 matrices g_dAffinetrans,
297a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// and g_dAffinetransPan using the specified 3x3 affine
2981e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal// transformation between the first captured frame and the current frame.
299a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// The computed g_dAffinetrans is such that it warps the preview mosaic in
300a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// the last frame's coordinate system into the coordinate system of the
301a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// current frame. Thus, applying this transformation will create the current
302a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// frame mosaic but with the current frame missing. This frame will then be
303a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// pasted in by gWarper2 after translating it by g_dTranslationToFBOCenter.
304a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// The computed g_dAffinetransPan is such that it offsets the computed preview
305a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal// mosaic horizontally to make the viewfinder pan within the UI layout.
306eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalvoid UpdateWarpTransformation(float *trs)
307eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
308a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    double H[9], Hp[9], Htemp1[9], Htemp2[9], T[9];
309eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
310a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    for(int i = 0; i < 9; i++)
311eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    {
312a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gThisH1t[i] = trs[i];
313eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    }
314eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
31547f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // Alignment is done based on low-res data.
31647f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // To render the preview mosaic, the translation of the high-res mosaic is estimated to
31747f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // H2L_FACTOR x low-res-based tranlation.
31847f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gThisH1t[2] *= H2L_FACTOR;
31947f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gThisH1t[5] *= H2L_FACTOR;
32047f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen
321a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(T);
322a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    T[2] = -gCenterOffsetX;
323a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    T[5] = -gCenterOffsetY;
324a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
325a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // H = ( inv(gThisH1t) * gLastH1t ) * T
326a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(Htemp1);
327a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(Htemp2);
328a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(H);
329a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_InvertAffineTransform(Htemp1, gThisH1t);
330a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Htemp2, Htemp1, gLastH1t);
331a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(H, Htemp2, T);
332a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
333a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    for(int i = 0; i < 9; i++)
334a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    {
335a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gLastH1t[i] = gThisH1t[i];
336a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    }
3371e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
338eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    // Move the origin such that the frame is centered in the previewFBO
339a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // i.e. H = inv(T) * H
340a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    H[2] += gCenterOffsetX;
341a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    H[5] += gCenterOffsetY;
342eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
34347f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // Hp = inv(Km) * H * Km
34447f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // Km moves the coordinate system from openGL to image pixels so
3451e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    // that the alignment transform H can be applied to them.
34647f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // inv(Km) moves the coordinate system back to openGL normalized
3471e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    // coordinates so that the shader can correctly render it.
348a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(Htemp1);
349a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Htemp1, H, gKm);
350a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
351eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
352eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    ConvertAffine3x3toGL4x4(g_dAffinetrans, Hp);
353eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
354a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    ////////////////////////////////////////////////
355a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    ////// Compute g_dAffinetransPan now...   //////
356a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    ////////////////////////////////////////////////
357eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
358a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gThisTx = trs[2];
359eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
360a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    if(gPanViewfinder)
361a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    {
362a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPanOffset += (gThisTx - gLastTx) * VIEWFINDER_PAN_FACTOR_HORZ;
363a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    }
3641e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
3651e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gLastTx = gThisTx;
366d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    gPanViewfinder = continuePanningFBO(gPanOffset);
367eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
368a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(H);
369a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    H[2] = gPanOffset;
3701e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
37147f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // Hp = inv(Km) * H * Km
372a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(Htemp1);
373a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Htemp1, H, gKm);
374a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
3751e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
376d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    if (gIsLandscapeOrientation) {
377d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        ConvertAffine3x3toGL4x4(g_dAffinetransPan, Hp);
378d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    } else {
379d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // rotate Hp by 90 degress.
380d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        db_Multiply3x3_3x3(Htemp1, gRotation90, Hp);
381d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        ConvertAffine3x3toGL4x4(g_dAffinetransPan, Htemp1);
382d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    }
383eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
384eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
38541a2e9735136f372de95652d0828600282c8e967mbansalvoid AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR)
386eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
3871e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImageWidth[HR] = widthHR;
3881e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImageHeight[HR] = heightHR;
3891e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
3901e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImageWidth[LR] = widthLR;
3911e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImageHeight[LR] = heightLR;
39241a2e9735136f372de95652d0828600282c8e967mbansal
3931e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_wait(&gPreviewImage_semaphore);
3941e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImage[LR] = ImageUtils::allocateImage(gPreviewImageWidth[LR],
3951e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[LR], 4);
3961e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gPreviewImage[HR] = ImageUtils::allocateImage(gPreviewImageWidth[HR],
3971e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[HR], 4);
3981e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_post(&gPreviewImage_semaphore);
399eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
40047f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[HR];
40147f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[HR];
402eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
403a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // The origin is such that the current frame will sit with its center
404a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // at the center of the previewFBO
40547f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[HR] / 2);
40647f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[HR] / 2);
407a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
408a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gPanOffset = 0.0f;
409a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
410a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(gThisH1t);
411a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(gLastH1t);
412a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
413a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gPanViewfinder = true;
414a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
41547f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    int w = gPreviewImageWidth[HR];
41647f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    int h = gPreviewImageHeight[HR];
417a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
418a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    int wm = gPreviewFBOWidth;
419a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    int hm = gPreviewFBOHeight;
420a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
421a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // K is the transformation to map the canonical [-1,1] vertex coordinate
422a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // system to the [0,w] image coordinate system before applying the given
423a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // affine transformation trs.
424a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[0] = wm / 2.0 - 0.5;
425a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[1] = 0.0;
426a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[2] = wm / 2.0 - 0.5;
427a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[3] = 0.0;
428a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[4] = hm / 2.0 - 0.5;
429a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[5] = hm / 2.0 - 0.5;
430a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[6] = 0.0;
431a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[7] = 0.0;
432a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gKm[8] = 1.0;
433a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
434a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[0] = w / 2.0 - 0.5;
435a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[1] = 0.0;
436a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[2] = w / 2.0 - 0.5;
437a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[3] = 0.0;
438a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[4] = h / 2.0 - 0.5;
439a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[5] = h / 2.0 - 0.5;
440a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[6] = 0.0;
441a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[7] = 0.0;
442a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gK[8] = 1.0;
443a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
444a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(gKinv);
445a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_InvertCalibrationMatrix(gKinv, gK);
446a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
447a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(gKminv);
448a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_InvertCalibrationMatrix(gKminv, gKm);
449a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
450a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    //////////////////////////////////////////
451a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    ////// Compute g_Translation now... //////
452a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    //////////////////////////////////////////
453a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    double T[9], Tp[9], Ttemp[9];
454a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
455a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(T);
456a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    T[2] = gCenterOffsetX;
457a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    T[5] = gCenterOffsetY;
458a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
459a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // Tp = inv(K) * T * K
460a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Identity3x3(Ttemp);
461a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Ttemp, T, gK);
462a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    db_Multiply3x3_3x3(Tp, gKinv, Ttemp);
463a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
464a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    ConvertAffine3x3toGL4x4(g_dTranslationToFBOCenter, Tp);
465eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
4661e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    UpdateWarpTransformation(g_dIdent3x3);
467eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
468eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
469eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalvoid FreeTextureMemory()
470eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
4711e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_wait(&gPreviewImage_semaphore);
4721e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    ImageUtils::freeImage(gPreviewImage[LR]);
4731e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    ImageUtils::freeImage(gPreviewImage[HR]);
4741e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_post(&gPreviewImage_semaphore);
475eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
476eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
477eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansalextern "C"
478eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
479f93198f838d047572a5cdeaa66668b060985b937Angus Kong    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
480f93198f838d047572a5cdeaa66668b060985b937Angus Kong    JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);
4810f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT jint JNICALL Java_com_android_camera_MosaicRenderer_init(
482eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal            JNIEnv * env, jobject obj);
4830f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset(
484d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            JNIEnv * env, jobject obj,  jint width, jint height,
485d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            jboolean isLandscapeOrientation);
4860f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_preprocess(
48741a2e9735136f372de95652d0828600282c8e967mbansal            JNIEnv * env, jobject obj, jfloatArray stMatrix);
4880f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_transferGPUtoCPU(
48941a2e9735136f372de95652d0828600282c8e967mbansal            JNIEnv * env, jobject obj);
4900f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_step(
491eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal            JNIEnv * env, jobject obj);
4924fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_updateMatrix(
493eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal            JNIEnv * env, jobject obj);
4940f986735d15b2435091bf6e11fc9306c95a5c528Pin Ting    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping(
49541a2e9735136f372de95652d0828600282c8e967mbansal            JNIEnv * env, jobject obj, jboolean flag);
496eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal};
497eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
498f93198f838d047572a5cdeaa66668b060985b937Angus Kong
499f93198f838d047572a5cdeaa66668b060985b937Angus KongJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
500f93198f838d047572a5cdeaa66668b060985b937Angus Kong{
501f93198f838d047572a5cdeaa66668b060985b937Angus Kong    sem_init(&gPreviewImage_semaphore, 0, 1);
502f93198f838d047572a5cdeaa66668b060985b937Angus Kong
503f93198f838d047572a5cdeaa66668b060985b937Angus Kong    return JNI_VERSION_1_4;
504f93198f838d047572a5cdeaa66668b060985b937Angus Kong}
505f93198f838d047572a5cdeaa66668b060985b937Angus Kong
506f93198f838d047572a5cdeaa66668b060985b937Angus Kong
507f93198f838d047572a5cdeaa66668b060985b937Angus KongJNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
508f93198f838d047572a5cdeaa66668b060985b937Angus Kong{
509f93198f838d047572a5cdeaa66668b060985b937Angus Kong    sem_destroy(&gPreviewImage_semaphore);
510f93198f838d047572a5cdeaa66668b060985b937Angus Kong}
5110f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT jint JNICALL Java_com_android_camera_MosaicRenderer_init(
512eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        JNIEnv * env, jobject obj)
513eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
51441a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].InitializeGLProgram();
51541a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].InitializeGLProgram();
5161e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[LR].InitializeGLProgram();
5171e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[HR].InitializeGLProgram();
5181e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper1.InitializeGLProgram();
5191e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper2.InitializeGLProgram();
520eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    gPreview.InitializeGLProgram();
5211e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBuffer[0].InitializeGLContext();
5221e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBuffer[1].InitializeGLContext();
52341a2e9735136f372de95652d0828600282c8e967mbansal    gBufferInput[LR].InitializeGLContext();
52441a2e9735136f372de95652d0828600282c8e967mbansal    gBufferInput[HR].InitializeGLContext();
5251e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInputYVU[LR].InitializeGLContext();
5261e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInputYVU[HR].InitializeGLContext();
527eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
528eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    glBindFramebuffer(GL_FRAMEBUFFER, 0);
52941a2e9735136f372de95652d0828600282c8e967mbansal
53041a2e9735136f372de95652d0828600282c8e967mbansal    glGenTextures(1, gSurfaceTextureID);
53141a2e9735136f372de95652d0828600282c8e967mbansal    // bind the surface texture
53241a2e9735136f372de95652d0828600282c8e967mbansal    bindSurfaceTexture(gSurfaceTextureID[0]);
53341a2e9735136f372de95652d0828600282c8e967mbansal
53441a2e9735136f372de95652d0828600282c8e967mbansal    return (jint) gSurfaceTextureID[0];
535eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
536eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
537445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li// width: the width of the view
538445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li// height: the height of the view
539445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li// isLandscape: whether the device is in landscape or portrait. Android
540445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li//     Compatibility Definition Document specifies that the long side of the
541445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li//     camera aligns with the long side of the screen.
542d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chenvoid calculateUILayoutScaling(int width, int height, bool isLandscape) {
543d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    if (isLandscape) {
544445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        //  __________        ________
545445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // |          |  =>  |________|
546445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // |__________|  =>    (View)
547445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // (Preview FBO)
548d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        //
549d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // Scale the preview FBO's height to the height of view and
550d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // maintain the aspect ratio of the current frame on the screen.
551d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE;
552d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
553d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // Note that OpenGL scales a texture to view's width and height automatically.
554d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // The "width / height" inverts the scaling, so as to maintain the aspect ratio
555d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // of the current frame.
556445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        gUILayoutScalingX = ((float) gPreviewFBOWidth / gPreviewFBOHeight)
557445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li                / ((float) width / height) * PREVIEW_FBO_HEIGHT_SCALE;
558d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    } else {
559445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        //                   ___
560445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        //  __________      |   |     ______
561445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // |          |  => |   | => |______|
562445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // |__________|  => |   | =>  (View)
563445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // (Preview FBO)    |   |
564445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        //                  |___|
565445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        //
566d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // Scale the preview FBO's height to the width of view and
567d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // maintain the aspect ratio of the current frame on the screen.
568445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // In preview, Java_com_android_camera_MosaicRenderer_step rotates the
569445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // preview FBO by 90 degrees. In capture, UpdateWarpTransformation
570445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        // rotates the preview FBO.
571445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        gUILayoutScalingY = PREVIEW_FBO_WIDTH_SCALE;
572d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
573d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // Note that OpenGL scales a texture to view's width and height automatically.
574d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // The "height / width" inverts the scaling, so as to maintain the aspect ratio
575d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // of the current frame.
576445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li        gUILayoutScalingX = ((float) gPreviewFBOHeight / gPreviewFBOWidth)
577445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li                / ((float) width / height) * PREVIEW_FBO_WIDTH_SCALE;
578d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    }
579d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen}
580d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
5810f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset(
582d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        JNIEnv * env, jobject obj,  jint width, jint height, jboolean isLandscapeOrientation)
583eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
584d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    gIsLandscapeOrientation = isLandscapeOrientation;
585d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    calculateUILayoutScaling(width, height, gIsLandscapeOrientation);
58685dedb803016feea39a78efc4bfc07b4f436cc6cWei-Ta Chen
5871e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
5881e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
5891e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
5901e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInput[LR].Init(gPreviewImageWidth[LR],
5911e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[LR], GL_RGBA);
5921e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
5931e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInput[HR].Init(gPreviewImageWidth[HR],
5941e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[HR], GL_RGBA);
59541a2e9735136f372de95652d0828600282c8e967mbansal
5961e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInputYVU[LR].Init(gPreviewImageWidth[LR],
5971e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[LR], GL_RGBA);
59841a2e9735136f372de95652d0828600282c8e967mbansal
5991e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gBufferInputYVU[HR].Init(gPreviewImageWidth[HR],
6001e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal            gPreviewImageHeight[HR], GL_RGBA);
601eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
60241a2e9735136f372de95652d0828600282c8e967mbansal    // bind the surface texture
60341a2e9735136f372de95652d0828600282c8e967mbansal    bindSurfaceTexture(gSurfaceTextureID[0]);
60441a2e9735136f372de95652d0828600282c8e967mbansal
605b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // To speed up, there is no need to clear the destination buffers
606b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // (offscreen/screen buffers) of gSurfTexRenderer, gYVURenderer
607b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // and gPreview because we always fill the whole destination buffers
608b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // when we draw something to those offscreen/screen buffers.
60941a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetupGraphics(&gBufferInput[LR]);
61041a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetViewportMatrix(1, 1, 1, 1);
61141a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetScalingMatrix(1.0f, -1.0f);
61241a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetInputTextureName(gSurfaceTextureID[0]);
61341a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
614eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
61541a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetupGraphics(&gBufferInput[HR]);
61641a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetViewportMatrix(1, 1, 1, 1);
61741a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetScalingMatrix(1.0f, -1.0f);
61841a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetInputTextureName(gSurfaceTextureID[0]);
61941a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
62041a2e9735136f372de95652d0828600282c8e967mbansal
6211e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[LR].SetupGraphics(&gBufferInputYVU[LR]);
6221e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[LR].SetInputTextureName(gBufferInput[LR].GetTextureName());
6231e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[LR].SetInputTextureType(GL_TEXTURE_2D);
6241e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6251e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[HR].SetupGraphics(&gBufferInputYVU[HR]);
6261e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[HR].SetInputTextureName(gBufferInput[HR].GetTextureName());
6271e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[HR].SetInputTextureType(GL_TEXTURE_2D);
6281e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
629a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    // gBuffer[1-gCurrentFBOIndex] --> gWarper1 --> gBuffer[gCurrentFBOIndex]
6301e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
631b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen
632b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // Clear the destination buffer of gWarper1.
6331e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
634a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gWarper1.SetViewportMatrix(1, 1, 1, 1);
6351e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper1.SetScalingMatrix(1.0f, 1.0f);
636a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName());
6371e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper1.SetInputTextureType(GL_TEXTURE_2D);
6381e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
63947f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    // gBufferInput[HR] --> gWarper2 --> gBuffer[gCurrentFBOIndex]
640a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
641b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen
642b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // gWarp2's destination buffer is the same to gWarp1's. No need to clear it
643b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // again.
64447f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gWarper2.SetViewportMatrix(gPreviewImageWidth[HR],
64547f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen            gPreviewImageHeight[HR], gBuffer[gCurrentFBOIndex].GetWidth(),
646a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal            gBuffer[gCurrentFBOIndex].GetHeight());
6471e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper2.SetScalingMatrix(1.0f, 1.0f);
64847f3bff0df080af493ddae1857b82370b592e2f7Wei-Ta Chen    gWarper2.SetInputTextureName(gBufferInput[HR].GetTextureName());
6491e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gWarper2.SetInputTextureType(GL_TEXTURE_2D);
650eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
651b96ce59e1d477622f9a3c235135d7040f642e262Wei-Ta Chen    // gBuffer[gCurrentFBOIndex] --> gPreview --> Screen
652eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    gPreview.SetupGraphics(width, height);
653eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    gPreview.SetViewportMatrix(1, 1, 1, 1);
654d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
6551e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    // Scale the previewFBO so that the viewfinder window fills the layout height
6561e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    // while maintaining the image aspect ratio
657a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY);
658a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
65941a2e9735136f372de95652d0828600282c8e967mbansal    gPreview.SetInputTextureType(GL_TEXTURE_2D);
66041a2e9735136f372de95652d0828600282c8e967mbansal}
66141a2e9735136f372de95652d0828600282c8e967mbansal
6620f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_preprocess(
66341a2e9735136f372de95652d0828600282c8e967mbansal        JNIEnv * env, jobject obj, jfloatArray stMatrix)
66441a2e9735136f372de95652d0828600282c8e967mbansal{
66541a2e9735136f372de95652d0828600282c8e967mbansal    jfloat *stmat = env->GetFloatArrayElements(stMatrix, 0);
66641a2e9735136f372de95652d0828600282c8e967mbansal
66741a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[LR].SetSTMatrix((float*) stmat);
66841a2e9735136f372de95652d0828600282c8e967mbansal    gSurfTexRenderer[HR].SetSTMatrix((float*) stmat);
66941a2e9735136f372de95652d0828600282c8e967mbansal
67041a2e9735136f372de95652d0828600282c8e967mbansal    env->ReleaseFloatArrayElements(stMatrix, stmat, 0);
67141a2e9735136f372de95652d0828600282c8e967mbansal
672d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    gSurfTexRenderer[LR].DrawTexture(g_dAffinetransIdentGL);
673d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen    gSurfTexRenderer[HR].DrawTexture(g_dAffinetransIdentGL);
67441a2e9735136f372de95652d0828600282c8e967mbansal}
67541a2e9735136f372de95652d0828600282c8e967mbansal
6761e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal#ifndef now_ms
6771e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal#include <time.h>
6781e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalstatic double
6791e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalnow_ms(void)
6801e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal{
6811e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    //struct timespec res;
6821e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    struct timeval res;
6831e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    //clock_gettime(CLOCK_REALTIME, &res);
6841e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gettimeofday(&res, NULL);
6851e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
6861e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal}
6871e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal#endif
6881e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6891e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6901e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6910f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_transferGPUtoCPU(
69241a2e9735136f372de95652d0828600282c8e967mbansal        JNIEnv * env, jobject obj)
69341a2e9735136f372de95652d0828600282c8e967mbansal{
6941e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    double t0, t1, time_c;
6951e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6961e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[LR].DrawTexture();
6971e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    gYVURenderer[HR].DrawTexture();
6981e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
6991e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_wait(&gPreviewImage_semaphore);
70041a2e9735136f372de95652d0828600282c8e967mbansal    // Bind to the input LR FBO and read the Low-Res data from there...
7011e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[LR].GetFrameBufferName());
7021e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    t0 = now_ms();
70341a2e9735136f372de95652d0828600282c8e967mbansal    glReadPixels(0,
70441a2e9735136f372de95652d0828600282c8e967mbansal                 0,
70541a2e9735136f372de95652d0828600282c8e967mbansal                 gBufferInput[LR].GetWidth(),
70641a2e9735136f372de95652d0828600282c8e967mbansal                 gBufferInput[LR].GetHeight(),
70741a2e9735136f372de95652d0828600282c8e967mbansal                 GL_RGBA,
70841a2e9735136f372de95652d0828600282c8e967mbansal                 GL_UNSIGNED_BYTE,
7091e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal                 gPreviewImage[LR]);
71041a2e9735136f372de95652d0828600282c8e967mbansal
7114fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    checkGlError("glReadPixels LR (MosaicRenderer.transferGPUtoCPU())");
71241a2e9735136f372de95652d0828600282c8e967mbansal
71341a2e9735136f372de95652d0828600282c8e967mbansal    // Bind to the input HR FBO and read the high-res data from there...
7141e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[HR].GetFrameBufferName());
7151e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    t0 = now_ms();
71641a2e9735136f372de95652d0828600282c8e967mbansal    glReadPixels(0,
71741a2e9735136f372de95652d0828600282c8e967mbansal                 0,
71841a2e9735136f372de95652d0828600282c8e967mbansal                 gBufferInput[HR].GetWidth(),
71941a2e9735136f372de95652d0828600282c8e967mbansal                 gBufferInput[HR].GetHeight(),
72041a2e9735136f372de95652d0828600282c8e967mbansal                 GL_RGBA,
72141a2e9735136f372de95652d0828600282c8e967mbansal                 GL_UNSIGNED_BYTE,
7221e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal                 gPreviewImage[HR]);
72341a2e9735136f372de95652d0828600282c8e967mbansal
7244fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus Kong    checkGlError("glReadPixels HR (MosaicRenderer.transferGPUtoCPU())");
72541a2e9735136f372de95652d0828600282c8e967mbansal
7261e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    sem_post(&gPreviewImage_semaphore);
727eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
728eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
7290f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_step(
730eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        JNIEnv * env, jobject obj)
731eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
732a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal    if(!gWarpImage) // ViewFinder
7331e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    {
734a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
7351e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
7361e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
737a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
738d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen
739d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        if (gIsLandscapeOrientation) {
740d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gPreview.DrawTexture(g_dAffinetransIdentGL);
741d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        } else {
742d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen            gPreview.DrawTexture(g_dAffinetransRotation90GL);
743d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        }
7441e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    }
7451e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    else
7461e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    {
7471e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
748a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        // Clear the destination so that we can paint on it afresh
749a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
750a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper1.SetInputTextureName(
751a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal                gBuffer[1 - gCurrentFBOIndex].GetTextureName());
752a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
753a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
754eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
7551e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        gWarper1.DrawTexture(g_dAffinetransGL);
756a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
757a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPreview.DrawTexture(g_dAffinetransPanGL);
7581e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
7591e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        gCurrentFBOIndex = 1 - gCurrentFBOIndex;
7601e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    }
761eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
762eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
7630f986735d15b2435091bf6e11fc9306c95a5c528Pin TingJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping(
76441a2e9735136f372de95652d0828600282c8e967mbansal        JNIEnv * env, jobject obj, jboolean flag)
765eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
76641a2e9735136f372de95652d0828600282c8e967mbansal    // TODO: Review this logic
76741a2e9735136f372de95652d0828600282c8e967mbansal    if(gWarpImage != (bool) flag) //switching from viewfinder to capture or vice-versa
76841a2e9735136f372de95652d0828600282c8e967mbansal    {
769a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        // Clear gBuffer[0]
770a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper1.SetupGraphics(&gBuffer[0]);
771a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
772a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        // Clear gBuffer[1]
773a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gWarper1.SetupGraphics(&gBuffer[1]);
7741e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
77541a2e9735136f372de95652d0828600282c8e967mbansal        // Clear the screen to black.
776a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPreview.Clear(0.0, 0.0, 0.0, 1.0);
777a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
778a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gLastTx = 0.0f;
779a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPanOffset = 0.0f;
780a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        gPanViewfinder = true;
781a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
782a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        db_Identity3x3(gThisH1t);
783a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        db_Identity3x3(gLastH1t);
784ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li        // Make sure g_dAffinetransGL and g_dAffinetransPanGL are updated.
785ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li        // Otherwise, the first frame after setting the flag to true will be
786ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li        // incorrectly drawn.
787ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li        if ((bool) flag) {
788ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li            UpdateWarpTransformation(g_dIdent3x3);
789ee1ff397d5c8cd98b4396031e2b39e48962f5f75Wu-cheng Li        }
79041a2e9735136f372de95652d0828600282c8e967mbansal    }
791a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal
79241a2e9735136f372de95652d0828600282c8e967mbansal    gWarpImage = (bool)flag;
793eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
794eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
7954fabf52f7e8b2419749f5cdc03925d5f8b1c0199Angus KongJNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_updateMatrix(
796eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        JNIEnv * env, jobject obj)
797eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal{
798eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    for(int i=0; i<16; i++)
799eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    {
800eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        g_dAffinetransGL[i] = g_dAffinetrans[i];
801a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        g_dAffinetransPanGL[i] = g_dAffinetransPan[i];
802a6f0b9e759fa2d19d493bde7ffa8105ec2978b94mbansal        g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i];
803eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    }
804eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal}
805