Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <GLES2/gl2.h>
     18 #include <GLES2/gl2ext.h>
     19 #include <jni.h>
     20 #include <math.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include "db_utilities_camera.h"
     24 #include "mosaic/ImageUtils.h"
     25 #include "mosaic_renderer/FrameBuffer.h"
     26 #include "mosaic_renderer/WarpRenderer.h"
     27 #include "mosaic_renderer/SurfaceTextureRenderer.h"
     28 #include "mosaic_renderer/YVURenderer.h"
     29 
     30 #include "mosaic/Log.h"
     31 #define LOG_TAG "MosaicRenderer"
     32 
     33 #include "mosaic_renderer_jni.h"
     34 
     35 // Texture handle
     36 GLuint gSurfaceTextureID[1];
     37 
     38 bool gWarpImage = true;
     39 
     40 // Low-Res input image frame in YUVA format for preview rendering and processing
     41 // and high-res YUVA input image for processing.
     42 unsigned char* gPreviewImage[NR];
     43 // Low-Res & high-res preview image width
     44 int gPreviewImageWidth[NR];
     45 // Low-Res & high-res preview image height
     46 int gPreviewImageHeight[NR];
     47 
     48 // Semaphore to protect simultaneous read/writes from gPreviewImage
     49 sem_t gPreviewImage_semaphore;
     50 
     51 // Off-screen preview FBO width (large enough to store the entire
     52 // preview mosaic).
     53 int gPreviewFBOWidth;
     54 // Off-screen preview FBO height (large enough to store the entire
     55 // preview mosaic).
     56 int gPreviewFBOHeight;
     57 
     58 // gK is the transformation to map the canonical {-1,1} vertex coordinate system
     59 // to the {0,gPreviewImageWidth[LR]} input image frame coordinate system before
     60 // applying the given affine transformation trs. gKm is the corresponding
     61 // transformation for going to the {0,gPreviewFBOWidth}.
     62 double gK[9];
     63 double gKinv[9];
     64 double gKm[9];
     65 double gKminv[9];
     66 
     67 // Shader to copy input SurfaceTexture into and RGBA FBO. The two shaders
     68 // render to the textures with dimensions corresponding to the low-res and
     69 // high-res image frames.
     70 SurfaceTextureRenderer gSurfTexRenderer[NR];
     71 // Off-screen FBOs to store the low-res and high-res RGBA copied out from
     72 // the SurfaceTexture by the gSurfTexRenderers.
     73 FrameBuffer gBufferInput[NR];
     74 
     75 // Shader to convert RGBA textures into YVU textures for processing
     76 YVURenderer gYVURenderer[NR];
     77 // Off-screen FBOs to store the low-res and high-res YVU textures for processing
     78 FrameBuffer gBufferInputYVU[NR];
     79 
     80 // Shader to translate the flip-flop FBO - gBuffer[1-current] -> gBuffer[current]
     81 WarpRenderer gWarper1;
     82 // Shader to add warped current frame to the flip-flop FBO - gBuffer[current]
     83 WarpRenderer gWarper2;
     84 // Off-screen FBOs (flip-flop) to store the result of gWarper1 & gWarper2
     85 FrameBuffer gBuffer[2];
     86 
     87 // Shader to warp and render the preview FBO to the screen
     88 WarpRenderer gPreview;
     89 
     90 // Index of the gBuffer FBO gWarper1 is going to write into
     91 int gCurrentFBOIndex = 0;
     92 
     93 // 3x3 Matrices holding the transformation of this frame (gThisH1t) and of
     94 // the last frame (gLastH1t) w.r.t the first frame.
     95 double gThisH1t[9];
     96 double gLastH1t[9];
     97 
     98 // Variables to represent the fixed position of the top-left corner of the
     99 // current frame in the previewFBO
    100 double gCenterOffsetX = 0.0f;
    101 double gCenterOffsetY = 0.0f;
    102 
    103 // X-Offset of the viewfinder (current frame) w.r.t
    104 // (gCenterOffsetX, gCenterOffsetY). This offset varies with time and is
    105 // used to pan the viewfinder across the UI layout.
    106 double gPanOffset = 0.0f;
    107 
    108 // Variables tracking the translation value for the current frame and the
    109 // last frame (both w.r.t the first frame). The difference between these
    110 // values is used to control the panning speed of the viewfinder display
    111 // on the UI screen.
    112 double gThisTx = 0.0f;
    113 double gLastTx = 0.0f;
    114 
    115 // These are the scale factors used by the gPreview shader to ensure that
    116 // the image frame is correctly scaled to the full UI layout height while
    117 // maintaining its aspect ratio
    118 double gUILayoutScalingX = 1.0f;
    119 double gUILayoutScalingY = 1.0f;
    120 
    121 // Whether the view that we will render preview FBO onto is in landscape or portrait
    122 // orientation.
    123 bool gIsLandscapeOrientation = true;
    124 
    125 // State of the viewfinder. Set to false when the viewfinder hits the UI edge.
    126 bool gPanViewfinder = true;
    127 
    128 // Affine transformation in GL 4x4 format (column-major) to warp the
    129 // last frame mosaic into the current frame coordinate system.
    130 GLfloat g_dAffinetransGL[16];
    131 double g_dAffinetrans[16];
    132 
    133 // Affine transformation in GL 4x4 format (column-major) to translate the
    134 // preview FBO across the screen (viewfinder panning).
    135 GLfloat g_dAffinetransPanGL[16];
    136 double g_dAffinetransPan[16];
    137 
    138 // XY translation in GL 4x4 format (column-major) to center the current
    139 // preview mosaic in the preview FBO
    140 GLfloat g_dTranslationToFBOCenterGL[16];
    141 double g_dTranslationToFBOCenter[16];
    142 
    143 // GL 4x4 Identity transformation
    144 GLfloat g_dAffinetransIdentGL[] = {
    145     1., 0., 0., 0.,
    146     0., 1., 0., 0.,
    147     0., 0., 1., 0.,
    148     0., 0., 0., 1.};
    149 
    150 // GL 4x4 Rotation transformation (column-majored): 90 degree
    151 GLfloat g_dAffinetransRotation90GL[] = {
    152     0., 1., 0., 0.,
    153     -1., 0., 0., 0.,
    154     0., 0., 1., 0.,
    155     0., 0., 0., 1.};
    156 
    157 // 3x3 Rotation transformation (row-majored): 90 degree
    158 double gRotation90[] = {
    159     0., -1., 0.,
    160     1., 0., 0.,
    161     0., 0., 1.,};
    162 
    163 
    164 float g_dIdent3x3[] = {
    165     1.0, 0.0, 0.0,
    166     0.0, 1.0, 0.0,
    167     0.0, 0.0, 1.0};
    168 
    169 const int GL_TEXTURE_EXTERNAL_OES_ENUM = 0x8D65;
    170 
    171 static void printGLString(const char *name, GLenum s) {
    172     const char *v = (const char *) glGetString(s);
    173     LOGI("GL %s = %s", name, v);
    174 }
    175 
    176 // @return false if there was an error
    177 bool checkGlError(const char* op) {
    178     GLint error = glGetError();
    179     if (error != 0) {
    180         LOGE("after %s() glError (0x%x)", op, error);
    181         return false;
    182     }
    183     return true;
    184 }
    185 
    186 void bindSurfaceTexture(GLuint texId)
    187 {
    188     glBindTexture(GL_TEXTURE_EXTERNAL_OES_ENUM, texId);
    189 
    190     // Can't do mipmapping with camera source
    191     glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MIN_FILTER,
    192             GL_LINEAR);
    193     glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MAG_FILTER,
    194             GL_LINEAR);
    195     // Clamp to edge is the only option
    196     glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_S,
    197             GL_CLAMP_TO_EDGE);
    198     glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_T,
    199             GL_CLAMP_TO_EDGE);
    200 }
    201 
    202 void ClearPreviewImage(int mID)
    203 {
    204     unsigned char* ptr = gPreviewImage[mID];
    205     for(int j = 0, i = 0;
    206             j < gPreviewImageWidth[mID] * gPreviewImageHeight[mID] * 4;
    207             j += 4)
    208     {
    209             ptr[i++] = 0;
    210             ptr[i++] = 0;
    211             ptr[i++] = 0;
    212             ptr[i++] = 255;
    213     }
    214 
    215 }
    216 
    217 void ConvertAffine3x3toGL4x4(double *matGL44, double *mat33)
    218 {
    219     matGL44[0] = mat33[0];
    220     matGL44[1] = mat33[3];
    221     matGL44[2] = 0.0;
    222     matGL44[3] = mat33[6];
    223 
    224     matGL44[4] = mat33[1];
    225     matGL44[5] = mat33[4];
    226     matGL44[6] = 0.0;
    227     matGL44[7] = mat33[7];
    228 
    229     matGL44[8] = 0;
    230     matGL44[9] = 0;
    231     matGL44[10] = 1.0;
    232     matGL44[11] = 0.0;
    233 
    234     matGL44[12] = mat33[2];
    235     matGL44[13] = mat33[5];
    236     matGL44[14] = 0.0;
    237     matGL44[15] = mat33[8];
    238 }
    239 
    240 bool continuePanningFBO(double panOffset) {
    241     double normalizedScreenLimitLeft = -1.0 + VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
    242     double normalizedScreenLimitRight = 1.0 - VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
    243     double normalizedXPositionOnScreenLeft;
    244     double normalizedXPositionOnScreenRight;
    245 
    246     // Compute the position of the current frame in the screen coordinate system
    247     if (gIsLandscapeOrientation) {
    248         normalizedXPositionOnScreenLeft = (2.0 *
    249             (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
    250             gUILayoutScalingX;
    251         normalizedXPositionOnScreenRight = (2.0 *
    252             ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
    253             gPreviewFBOWidth - 1.0) * gUILayoutScalingX;
    254     } else {
    255         normalizedXPositionOnScreenLeft = (2.0 *
    256             (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
    257             gUILayoutScalingY;
    258         normalizedXPositionOnScreenRight = (2.0 *
    259             ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
    260             gPreviewFBOWidth - 1.0) * gUILayoutScalingY;
    261     }
    262 
    263     // Stop the viewfinder panning if we hit the maximum border allowed for
    264     // this UI layout
    265     if (normalizedXPositionOnScreenRight > normalizedScreenLimitRight ||
    266             normalizedXPositionOnScreenLeft < normalizedScreenLimitLeft) {
    267         return false;
    268     } else {
    269         return true;
    270     }
    271 }
    272 
    273 // This function computes fills the 4x4 matrices g_dAffinetrans,
    274 // and g_dAffinetransPan using the specified 3x3 affine
    275 // transformation between the first captured frame and the current frame.
    276 // The computed g_dAffinetrans is such that it warps the preview mosaic in
    277 // the last frame's coordinate system into the coordinate system of the
    278 // current frame. Thus, applying this transformation will create the current
    279 // frame mosaic but with the current frame missing. This frame will then be
    280 // pasted in by gWarper2 after translating it by g_dTranslationToFBOCenter.
    281 // The computed g_dAffinetransPan is such that it offsets the computed preview
    282 // mosaic horizontally to make the viewfinder pan within the UI layout.
    283 void UpdateWarpTransformation(float *trs)
    284 {
    285     double H[9], Hp[9], Htemp1[9], Htemp2[9], T[9];
    286 
    287     for(int i = 0; i < 9; i++)
    288     {
    289         gThisH1t[i] = trs[i];
    290     }
    291 
    292     // Alignment is done based on low-res data.
    293     // To render the preview mosaic, the translation of the high-res mosaic is estimated to
    294     // H2L_FACTOR x low-res-based tranlation.
    295     gThisH1t[2] *= H2L_FACTOR;
    296     gThisH1t[5] *= H2L_FACTOR;
    297 
    298     db_Identity3x3(T);
    299     T[2] = -gCenterOffsetX;
    300     T[5] = -gCenterOffsetY;
    301 
    302     // H = ( inv(gThisH1t) * gLastH1t ) * T
    303     db_Identity3x3(Htemp1);
    304     db_Identity3x3(Htemp2);
    305     db_Identity3x3(H);
    306     db_InvertAffineTransform(Htemp1, gThisH1t);
    307     db_Multiply3x3_3x3(Htemp2, Htemp1, gLastH1t);
    308     db_Multiply3x3_3x3(H, Htemp2, T);
    309 
    310     for(int i = 0; i < 9; i++)
    311     {
    312         gLastH1t[i] = gThisH1t[i];
    313     }
    314 
    315     // Move the origin such that the frame is centered in the previewFBO
    316     // i.e. H = inv(T) * H
    317     H[2] += gCenterOffsetX;
    318     H[5] += gCenterOffsetY;
    319 
    320     // Hp = inv(Km) * H * Km
    321     // Km moves the coordinate system from openGL to image pixels so
    322     // that the alignment transform H can be applied to them.
    323     // inv(Km) moves the coordinate system back to openGL normalized
    324     // coordinates so that the shader can correctly render it.
    325     db_Identity3x3(Htemp1);
    326     db_Multiply3x3_3x3(Htemp1, H, gKm);
    327     db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
    328 
    329     ConvertAffine3x3toGL4x4(g_dAffinetrans, Hp);
    330 
    331     ////////////////////////////////////////////////
    332     ////// Compute g_dAffinetransPan now...   //////
    333     ////////////////////////////////////////////////
    334 
    335     gThisTx = trs[2];
    336 
    337     if(gPanViewfinder)
    338     {
    339         gPanOffset += (gThisTx - gLastTx) * VIEWFINDER_PAN_FACTOR_HORZ;
    340     }
    341 
    342     gLastTx = gThisTx;
    343     gPanViewfinder = continuePanningFBO(gPanOffset);
    344 
    345     db_Identity3x3(H);
    346     H[2] = gPanOffset;
    347 
    348     // Hp = inv(Km) * H * Km
    349     db_Identity3x3(Htemp1);
    350     db_Multiply3x3_3x3(Htemp1, H, gKm);
    351     db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
    352 
    353     if (gIsLandscapeOrientation) {
    354         ConvertAffine3x3toGL4x4(g_dAffinetransPan, Hp);
    355     } else {
    356         // rotate Hp by 90 degress.
    357         db_Multiply3x3_3x3(Htemp1, gRotation90, Hp);
    358         ConvertAffine3x3toGL4x4(g_dAffinetransPan, Htemp1);
    359     }
    360 }
    361 
    362 void AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR)
    363 {
    364     gPreviewImageWidth[HR] = widthHR;
    365     gPreviewImageHeight[HR] = heightHR;
    366 
    367     gPreviewImageWidth[LR] = widthLR;
    368     gPreviewImageHeight[LR] = heightLR;
    369 
    370     sem_init(&gPreviewImage_semaphore, 0, 1);
    371 
    372     sem_wait(&gPreviewImage_semaphore);
    373     gPreviewImage[LR] = ImageUtils::allocateImage(gPreviewImageWidth[LR],
    374             gPreviewImageHeight[LR], 4);
    375     ClearPreviewImage(LR);
    376     gPreviewImage[HR] = ImageUtils::allocateImage(gPreviewImageWidth[HR],
    377             gPreviewImageHeight[HR], 4);
    378     ClearPreviewImage(HR);
    379     sem_post(&gPreviewImage_semaphore);
    380 
    381     gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[HR];
    382     gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[HR];
    383 
    384     // The origin is such that the current frame will sit with its center
    385     // at the center of the previewFBO
    386     gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[HR] / 2);
    387     gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[HR] / 2);
    388 
    389     gPanOffset = 0.0f;
    390 
    391     db_Identity3x3(gThisH1t);
    392     db_Identity3x3(gLastH1t);
    393 
    394     gPanViewfinder = true;
    395 
    396     int w = gPreviewImageWidth[HR];
    397     int h = gPreviewImageHeight[HR];
    398 
    399     int wm = gPreviewFBOWidth;
    400     int hm = gPreviewFBOHeight;
    401 
    402     // K is the transformation to map the canonical [-1,1] vertex coordinate
    403     // system to the [0,w] image coordinate system before applying the given
    404     // affine transformation trs.
    405     gKm[0] = wm / 2.0 - 0.5;
    406     gKm[1] = 0.0;
    407     gKm[2] = wm / 2.0 - 0.5;
    408     gKm[3] = 0.0;
    409     gKm[4] = hm / 2.0 - 0.5;
    410     gKm[5] = hm / 2.0 - 0.5;
    411     gKm[6] = 0.0;
    412     gKm[7] = 0.0;
    413     gKm[8] = 1.0;
    414 
    415     gK[0] = w / 2.0 - 0.5;
    416     gK[1] = 0.0;
    417     gK[2] = w / 2.0 - 0.5;
    418     gK[3] = 0.0;
    419     gK[4] = h / 2.0 - 0.5;
    420     gK[5] = h / 2.0 - 0.5;
    421     gK[6] = 0.0;
    422     gK[7] = 0.0;
    423     gK[8] = 1.0;
    424 
    425     db_Identity3x3(gKinv);
    426     db_InvertCalibrationMatrix(gKinv, gK);
    427 
    428     db_Identity3x3(gKminv);
    429     db_InvertCalibrationMatrix(gKminv, gKm);
    430 
    431     //////////////////////////////////////////
    432     ////// Compute g_Translation now... //////
    433     //////////////////////////////////////////
    434     double T[9], Tp[9], Ttemp[9];
    435 
    436     db_Identity3x3(T);
    437     T[2] = gCenterOffsetX;
    438     T[5] = gCenterOffsetY;
    439 
    440     // Tp = inv(K) * T * K
    441     db_Identity3x3(Ttemp);
    442     db_Multiply3x3_3x3(Ttemp, T, gK);
    443     db_Multiply3x3_3x3(Tp, gKinv, Ttemp);
    444 
    445     ConvertAffine3x3toGL4x4(g_dTranslationToFBOCenter, Tp);
    446 
    447     UpdateWarpTransformation(g_dIdent3x3);
    448 }
    449 
    450 void FreeTextureMemory()
    451 {
    452     sem_wait(&gPreviewImage_semaphore);
    453     ImageUtils::freeImage(gPreviewImage[LR]);
    454     ImageUtils::freeImage(gPreviewImage[HR]);
    455     sem_post(&gPreviewImage_semaphore);
    456 
    457     sem_destroy(&gPreviewImage_semaphore);
    458 }
    459 
    460 extern "C"
    461 {
    462     JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
    463             JNIEnv * env, jobject obj);
    464     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
    465             JNIEnv * env, jobject obj,  jint width, jint height,
    466             jboolean isLandscapeOrientation);
    467     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
    468             JNIEnv * env, jobject obj, jfloatArray stMatrix);
    469     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
    470             JNIEnv * env, jobject obj);
    471     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
    472             JNIEnv * env, jobject obj);
    473     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
    474             JNIEnv * env, jobject obj);
    475     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
    476             JNIEnv * env, jobject obj, jboolean flag);
    477 };
    478 
    479 JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
    480         JNIEnv * env, jobject obj)
    481 {
    482     gSurfTexRenderer[LR].InitializeGLProgram();
    483     gSurfTexRenderer[HR].InitializeGLProgram();
    484     gYVURenderer[LR].InitializeGLProgram();
    485     gYVURenderer[HR].InitializeGLProgram();
    486     gWarper1.InitializeGLProgram();
    487     gWarper2.InitializeGLProgram();
    488     gPreview.InitializeGLProgram();
    489     gBuffer[0].InitializeGLContext();
    490     gBuffer[1].InitializeGLContext();
    491     gBufferInput[LR].InitializeGLContext();
    492     gBufferInput[HR].InitializeGLContext();
    493     gBufferInputYVU[LR].InitializeGLContext();
    494     gBufferInputYVU[HR].InitializeGLContext();
    495 
    496     glBindFramebuffer(GL_FRAMEBUFFER, 0);
    497 
    498     glGenTextures(1, gSurfaceTextureID);
    499     // bind the surface texture
    500     bindSurfaceTexture(gSurfaceTextureID[0]);
    501 
    502     return (jint) gSurfaceTextureID[0];
    503 }
    504 
    505 
    506 void calculateUILayoutScaling(int width, int height, bool isLandscape) {
    507     if (isLandscape) {
    508         //  __________        ______
    509         // |__________|  =>  |______|
    510         // (Preview FBO)      (View)
    511         //
    512         // Scale the preview FBO's height to the height of view and
    513         // maintain the aspect ratio of the current frame on the screen.
    514         gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE;
    515 
    516         // Note that OpenGL scales a texture to view's width and height automatically.
    517         // The "width / height" inverts the scaling, so as to maintain the aspect ratio
    518         // of the current frame.
    519         gUILayoutScalingX = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
    520                 / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
    521                 / ((float) width / height);
    522     } else {
    523         //                     __
    524         //  __________        |  |
    525         // |__________|  =>   |  |
    526         // (Preview FBO)      |  |
    527         //                    |__|
    528         //                   (View)
    529         // Scale the preview FBO's height to the width of view and
    530         // maintain the aspect ratio of the current frame on the screen.
    531         gUILayoutScalingX = PREVIEW_FBO_HEIGHT_SCALE;
    532 
    533         // Note that OpenGL scales a texture to view's width and height automatically.
    534         // The "height / width" inverts the scaling, so as to maintain the aspect ratio
    535         // of the current frame.
    536         gUILayoutScalingY = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
    537                 / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
    538                 / ((float) height / width);
    539 
    540     }
    541 }
    542 
    543 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
    544         JNIEnv * env, jobject obj,  jint width, jint height, jboolean isLandscapeOrientation)
    545 {
    546     gIsLandscapeOrientation = isLandscapeOrientation;
    547     calculateUILayoutScaling(width, height, gIsLandscapeOrientation);
    548 
    549     gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
    550     gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
    551 
    552     gBufferInput[LR].Init(gPreviewImageWidth[LR],
    553             gPreviewImageHeight[LR], GL_RGBA);
    554 
    555     gBufferInput[HR].Init(gPreviewImageWidth[HR],
    556             gPreviewImageHeight[HR], GL_RGBA);
    557 
    558     gBufferInputYVU[LR].Init(gPreviewImageWidth[LR],
    559             gPreviewImageHeight[LR], GL_RGBA);
    560 
    561     gBufferInputYVU[HR].Init(gPreviewImageWidth[HR],
    562             gPreviewImageHeight[HR], GL_RGBA);
    563 
    564     sem_wait(&gPreviewImage_semaphore);
    565     ClearPreviewImage(LR);
    566     ClearPreviewImage(HR);
    567     sem_post(&gPreviewImage_semaphore);
    568 
    569     // bind the surface texture
    570     bindSurfaceTexture(gSurfaceTextureID[0]);
    571 
    572     gSurfTexRenderer[LR].SetupGraphics(&gBufferInput[LR]);
    573     gSurfTexRenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
    574     gSurfTexRenderer[LR].SetViewportMatrix(1, 1, 1, 1);
    575     gSurfTexRenderer[LR].SetScalingMatrix(1.0f, -1.0f);
    576     gSurfTexRenderer[LR].SetInputTextureName(gSurfaceTextureID[0]);
    577     gSurfTexRenderer[LR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
    578 
    579     gSurfTexRenderer[HR].SetupGraphics(&gBufferInput[HR]);
    580     gSurfTexRenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
    581     gSurfTexRenderer[HR].SetViewportMatrix(1, 1, 1, 1);
    582     gSurfTexRenderer[HR].SetScalingMatrix(1.0f, -1.0f);
    583     gSurfTexRenderer[HR].SetInputTextureName(gSurfaceTextureID[0]);
    584     gSurfTexRenderer[HR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
    585 
    586     gYVURenderer[LR].SetupGraphics(&gBufferInputYVU[LR]);
    587     gYVURenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
    588     gYVURenderer[LR].SetInputTextureName(gBufferInput[LR].GetTextureName());
    589     gYVURenderer[LR].SetInputTextureType(GL_TEXTURE_2D);
    590 
    591     gYVURenderer[HR].SetupGraphics(&gBufferInputYVU[HR]);
    592     gYVURenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
    593     gYVURenderer[HR].SetInputTextureName(gBufferInput[HR].GetTextureName());
    594     gYVURenderer[HR].SetInputTextureType(GL_TEXTURE_2D);
    595 
    596     // gBuffer[1-gCurrentFBOIndex] --> gWarper1 --> gBuffer[gCurrentFBOIndex]
    597     gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
    598     gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
    599     gWarper1.SetViewportMatrix(1, 1, 1, 1);
    600     gWarper1.SetScalingMatrix(1.0f, 1.0f);
    601     gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName());
    602     gWarper1.SetInputTextureType(GL_TEXTURE_2D);
    603 
    604     // gBufferInput[HR] --> gWarper2 --> gBuffer[gCurrentFBOIndex]
    605     gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
    606     gWarper2.Clear(0.0, 0.0, 0.0, 1.0);
    607     gWarper2.SetViewportMatrix(gPreviewImageWidth[HR],
    608             gPreviewImageHeight[HR], gBuffer[gCurrentFBOIndex].GetWidth(),
    609             gBuffer[gCurrentFBOIndex].GetHeight());
    610     gWarper2.SetScalingMatrix(1.0f, 1.0f);
    611     gWarper2.SetInputTextureName(gBufferInput[HR].GetTextureName());
    612     gWarper2.SetInputTextureType(GL_TEXTURE_2D);
    613 
    614     gPreview.SetupGraphics(width, height);
    615     gPreview.Clear(0.0, 0.0, 0.0, 1.0);
    616     gPreview.SetViewportMatrix(1, 1, 1, 1);
    617 
    618     // Scale the previewFBO so that the viewfinder window fills the layout height
    619     // while maintaining the image aspect ratio
    620     gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY);
    621     gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
    622     gPreview.SetInputTextureType(GL_TEXTURE_2D);
    623 }
    624 
    625 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
    626         JNIEnv * env, jobject obj, jfloatArray stMatrix)
    627 {
    628     jfloat *stmat = env->GetFloatArrayElements(stMatrix, 0);
    629 
    630     gSurfTexRenderer[LR].SetSTMatrix((float*) stmat);
    631     gSurfTexRenderer[HR].SetSTMatrix((float*) stmat);
    632 
    633     env->ReleaseFloatArrayElements(stMatrix, stmat, 0);
    634 
    635     gSurfTexRenderer[LR].DrawTexture(g_dAffinetransIdentGL);
    636     gSurfTexRenderer[HR].DrawTexture(g_dAffinetransIdentGL);
    637 }
    638 
    639 #ifndef now_ms
    640 #include <time.h>
    641 static double
    642 now_ms(void)
    643 {
    644     //struct timespec res;
    645     struct timeval res;
    646     //clock_gettime(CLOCK_REALTIME, &res);
    647     gettimeofday(&res, NULL);
    648     return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
    649 }
    650 #endif
    651 
    652 
    653 
    654 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
    655         JNIEnv * env, jobject obj)
    656 {
    657     double t0, t1, time_c;
    658 
    659     gYVURenderer[LR].DrawTexture();
    660     gYVURenderer[HR].DrawTexture();
    661 
    662     sem_wait(&gPreviewImage_semaphore);
    663     // Bind to the input LR FBO and read the Low-Res data from there...
    664     glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[LR].GetFrameBufferName());
    665     t0 = now_ms();
    666     glReadPixels(0,
    667                  0,
    668                  gBufferInput[LR].GetWidth(),
    669                  gBufferInput[LR].GetHeight(),
    670                  GL_RGBA,
    671                  GL_UNSIGNED_BYTE,
    672                  gPreviewImage[LR]);
    673 
    674     checkGlError("glReadPixels LR");
    675 
    676     // Bind to the input HR FBO and read the high-res data from there...
    677     glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[HR].GetFrameBufferName());
    678     t0 = now_ms();
    679     glReadPixels(0,
    680                  0,
    681                  gBufferInput[HR].GetWidth(),
    682                  gBufferInput[HR].GetHeight(),
    683                  GL_RGBA,
    684                  GL_UNSIGNED_BYTE,
    685                  gPreviewImage[HR]);
    686 
    687     checkGlError("glReadPixels HR");
    688 
    689     sem_post(&gPreviewImage_semaphore);
    690 }
    691 
    692 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
    693         JNIEnv * env, jobject obj)
    694 {
    695     if(!gWarpImage) // ViewFinder
    696     {
    697         gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
    698         gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
    699 
    700         gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
    701 
    702         if (gIsLandscapeOrientation) {
    703             gPreview.DrawTexture(g_dAffinetransIdentGL);
    704         } else {
    705             gPreview.DrawTexture(g_dAffinetransRotation90GL);
    706         }
    707     }
    708     else
    709     {
    710         gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
    711         // Clear the destination so that we can paint on it afresh
    712         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
    713         gWarper1.SetInputTextureName(
    714                 gBuffer[1 - gCurrentFBOIndex].GetTextureName());
    715         gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
    716         gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
    717 
    718         gWarper1.DrawTexture(g_dAffinetransGL);
    719         gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
    720         gPreview.DrawTexture(g_dAffinetransPanGL);
    721 
    722         gCurrentFBOIndex = 1 - gCurrentFBOIndex;
    723     }
    724 }
    725 
    726 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
    727         JNIEnv * env, jobject obj, jboolean flag)
    728 {
    729     // TODO: Review this logic
    730     if(gWarpImage != (bool) flag) //switching from viewfinder to capture or vice-versa
    731     {
    732         // Clear gBuffer[0]
    733         gWarper1.SetupGraphics(&gBuffer[0]);
    734         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
    735         // Clear gBuffer[1]
    736         gWarper1.SetupGraphics(&gBuffer[1]);
    737         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
    738         // Clear the screen to black.
    739         gPreview.Clear(0.0, 0.0, 0.0, 1.0);
    740 
    741         gLastTx = 0.0f;
    742         gPanOffset = 0.0f;
    743         gPanViewfinder = true;
    744 
    745         db_Identity3x3(gThisH1t);
    746         db_Identity3x3(gLastH1t);
    747     }
    748 
    749     gWarpImage = (bool)flag;
    750 }
    751 
    752 
    753 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
    754         JNIEnv * env, jobject obj)
    755 {
    756     for(int i=0; i<16; i++)
    757     {
    758         g_dAffinetransGL[i] = g_dAffinetrans[i];
    759         g_dAffinetransPanGL[i] = g_dAffinetransPan[i];
    760         g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i];
    761     }
    762 }
    763