blob: e741befdce262c2ff98a6cc7adf39698434a37ac [file] [log] [blame]
mbansaleeb94d42011-08-02 11:31:28 -04001// OpenGL ES 2.0 code
2#include <jni.h>
3#include <android/log.h>
4
5#include <db_utilities_camera.h>
6#include "mosaic/ImageUtils.h"
7#include "mosaic_renderer/FrameBuffer.h"
8#include "mosaic_renderer/WarpRenderer.h"
mbansal41a2e972011-08-08 20:23:02 -04009#include "mosaic_renderer/SurfaceTextureRenderer.h"
mbansal1e762b12011-08-16 10:01:20 -040010#include "mosaic_renderer/YVURenderer.h"
mbansaleeb94d42011-08-02 11:31:28 -040011#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14
15#include "mosaic_renderer_jni.h"
16
17#define LOG_TAG "MosaicRenderer"
18#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
mbansal41a2e972011-08-08 20:23:02 -040019#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
mbansaleeb94d42011-08-02 11:31:28 -040020#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
21
22// Texture handle
mbansal41a2e972011-08-08 20:23:02 -040023GLuint gSurfaceTextureID[1];
mbansaleeb94d42011-08-02 11:31:28 -040024
mbansal41a2e972011-08-08 20:23:02 -040025bool gWarpImage = true;
mbansaleeb94d42011-08-02 11:31:28 -040026
mbansal1e762b12011-08-16 10:01:20 -040027// Low-Res input image frame in YUVA format for preview rendering and processing
28// and high-res YUVA input image for processing.
29unsigned char* gPreviewImage[NR];
mbansal41a2e972011-08-08 20:23:02 -040030// Low-Res & high-res preview image width
mbansal1e762b12011-08-16 10:01:20 -040031int gPreviewImageWidth[NR];
mbansal41a2e972011-08-08 20:23:02 -040032// Low-Res & high-res preview image height
mbansal1e762b12011-08-16 10:01:20 -040033int gPreviewImageHeight[NR];
mbansaleeb94d42011-08-02 11:31:28 -040034
mbansal1e762b12011-08-16 10:01:20 -040035// Semaphore to protect simultaneous read/writes from gPreviewImage
36sem_t gPreviewImage_semaphore;
mbansaleeb94d42011-08-02 11:31:28 -040037
38// Off-screen preview FBO width (large enough to store the entire
39// preview mosaic).
40int gPreviewFBOWidth;
41// Off-screen preview FBO height (large enough to store the entire
42// preview mosaic).
43int gPreviewFBOHeight;
44
mbansala6f0b9e2011-08-19 10:18:54 -040045// gK is the transformation to map the canonical {-1,1} vertex coordinate system
46// to the {0,gPreviewImageWidth[LR]} input image frame coordinate system before
47// applying the given affine transformation trs. gKm is the corresponding
48// transformation for going to the {0,gPreviewFBOWidth}.
49double gK[9];
50double gKinv[9];
51double gKm[9];
52double gKminv[9];
53
mbansal41a2e972011-08-08 20:23:02 -040054// Shader to copy input SurfaceTexture into and RGBA FBO. The two shaders
55// render to the textures with dimensions corresponding to the low-res and
56// high-res image frames.
57SurfaceTextureRenderer gSurfTexRenderer[NR];
58// Off-screen FBOs to store the low-res and high-res RGBA copied out from
59// the SurfaceTexture by the gSurfTexRenderers.
60FrameBuffer gBufferInput[NR];
mbansal1e762b12011-08-16 10:01:20 -040061
62// Shader to convert RGBA textures into YVU textures for processing
63YVURenderer gYVURenderer[NR];
64// Off-screen FBOs to store the low-res and high-res YVU textures for processing
65FrameBuffer gBufferInputYVU[NR];
66
mbansaleeb94d42011-08-02 11:31:28 -040067// Shader to add warped current frame to the preview FBO
mbansal1e762b12011-08-16 10:01:20 -040068WarpRenderer gWarper1;
69// Shader to translate the preview FBO
70WarpRenderer gWarper2;
71// Off-screen FBOs (flip-flop) to store the result of gWarper1 & gWarper2
72FrameBuffer gBuffer[2];
73
mbansaleeb94d42011-08-02 11:31:28 -040074// Shader to warp and render the preview FBO to the screen
75WarpRenderer gPreview;
mbansal1e762b12011-08-16 10:01:20 -040076
77// Index of the gBuffer FBO gWarper1 is going to write into
78int gCurrentFBOIndex = 0;
79
mbansala6f0b9e2011-08-19 10:18:54 -040080// 3x3 Matrices holding the transformation of this frame (gThisH1t) and of
81// the last frame (gLastH1t) w.r.t the first frame.
82double gThisH1t[9];
83double gLastH1t[9];
84
85// Variables to represent the fixed position of the top-left corner of the
86// current frame in the previewFBO
87double gCenterOffsetX = 0.0f;
88double gCenterOffsetY = 0.0f;
89
90// X-Offset of the viewfinder (current frame) w.r.t
91// (gCenterOffsetX, gCenterOffsetY). This offset varies with time and is
92// used to pan the viewfinder across the UI layout.
93double gPanOffset = 0.0f;
mbansal1e762b12011-08-16 10:01:20 -040094
95// Variables tracking the translation value for the current frame and the
96// last frame (both w.r.t the first frame). The difference between these
97// values is used to control the panning speed of the viewfinder display
98// on the UI screen.
99double gThisTx = 0.0f;
100double gLastTx = 0.0f;
mbansaleeb94d42011-08-02 11:31:28 -0400101
mbansala6f0b9e2011-08-19 10:18:54 -0400102// These are the scale factors used by the gPreview shader to ensure that
103// the image frame is correctly scaled to the full UI layout height while
104// maintaining its aspect ratio
105double gUILayoutScalingX = 1.0f;
106double gUILayoutScalingY = 1.0f;
107
108// State of the viewfinder. Set to false when the viewfinder hits the UI edge.
109bool gPanViewfinder = true;
110
mbansaleeb94d42011-08-02 11:31:28 -0400111// Affine transformation in GL 4x4 format (column-major) to warp the
mbansala6f0b9e2011-08-19 10:18:54 -0400112// last frame mosaic into the current frame coordinate system.
mbansaleeb94d42011-08-02 11:31:28 -0400113GLfloat g_dAffinetransGL[16];
mbansala6f0b9e2011-08-19 10:18:54 -0400114double g_dAffinetrans[16];
mbansaleeb94d42011-08-02 11:31:28 -0400115
mbansala6f0b9e2011-08-19 10:18:54 -0400116// Affine transformation in GL 4x4 format (column-major) to translate the
117// preview FBO across the screen (viewfinder panning).
118GLfloat g_dAffinetransPanGL[16];
119double g_dAffinetransPan[16];
mbansaleeb94d42011-08-02 11:31:28 -0400120
mbansala6f0b9e2011-08-19 10:18:54 -0400121// XY translation in GL 4x4 format (column-major) to center the current
122// preview mosaic in the preview FBO
123GLfloat g_dTranslationToFBOCenterGL[16];
124double g_dTranslationToFBOCenter[16];
mbansal1e762b12011-08-16 10:01:20 -0400125
mbansaleeb94d42011-08-02 11:31:28 -0400126// GL 4x4 Identity transformation
127GLfloat g_dAffinetransIdent[] = {
128 1., 0., 0., 0.,
129 0., 1., 0., 0.,
130 0., 0., 1., 0.,
131 0., 0., 0., 1.};
132
mbansal1e762b12011-08-16 10:01:20 -0400133float g_dIdent3x3[] = {
134 1.0, 0.0, 0.0,
135 0.0, 1.0, 0.0,
136 0.0, 0.0, 1.0};
137
mbansal41a2e972011-08-08 20:23:02 -0400138const int GL_TEXTURE_EXTERNAL_OES_ENUM = 0x8D65;
mbansaleeb94d42011-08-02 11:31:28 -0400139
140static void printGLString(const char *name, GLenum s) {
141 const char *v = (const char *) glGetString(s);
142 LOGI("GL %s = %s\n", name, v);
143}
144
145// @return false if there was an error
146bool checkGlError(const char* op) {
147 GLint error = glGetError();
148 if (error != 0) {
149 LOGE("after %s() glError (0x%x)\n", op, error);
150 return false;
151 }
152 return true;
153}
154
mbansal41a2e972011-08-08 20:23:02 -0400155void bindSurfaceTexture(GLuint texId)
mbansaleeb94d42011-08-02 11:31:28 -0400156{
mbansal41a2e972011-08-08 20:23:02 -0400157 glBindTexture(GL_TEXTURE_EXTERNAL_OES_ENUM, texId);
mbansaleeb94d42011-08-02 11:31:28 -0400158
mbansal41a2e972011-08-08 20:23:02 -0400159 // Can't do mipmapping with camera source
160 glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MIN_FILTER,
161 GL_LINEAR);
162 glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MAG_FILTER,
163 GL_LINEAR);
164 // Clamp to edge is the only option
165 glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_S,
166 GL_CLAMP_TO_EDGE);
167 glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_T,
168 GL_CLAMP_TO_EDGE);
mbansaleeb94d42011-08-02 11:31:28 -0400169}
170
mbansal1e762b12011-08-16 10:01:20 -0400171void ClearPreviewImage(int mID)
mbansaleeb94d42011-08-02 11:31:28 -0400172{
mbansal1e762b12011-08-16 10:01:20 -0400173 unsigned char* ptr = gPreviewImage[mID];
mbansal41a2e972011-08-08 20:23:02 -0400174 for(int j = 0, i = 0;
mbansal1e762b12011-08-16 10:01:20 -0400175 j < gPreviewImageWidth[mID] * gPreviewImageHeight[mID] * 4;
mbansal41a2e972011-08-08 20:23:02 -0400176 j += 4)
177 {
178 ptr[i++] = 0;
179 ptr[i++] = 0;
180 ptr[i++] = 0;
181 ptr[i++] = 255;
182 }
mbansaleeb94d42011-08-02 11:31:28 -0400183
mbansaleeb94d42011-08-02 11:31:28 -0400184}
185
186void ConvertAffine3x3toGL4x4(double *matGL44, double *mat33)
187{
188 matGL44[0] = mat33[0];
189 matGL44[1] = mat33[3];
190 matGL44[2] = 0.0;
191 matGL44[3] = mat33[6];
192
193 matGL44[4] = mat33[1];
194 matGL44[5] = mat33[4];
195 matGL44[6] = 0.0;
196 matGL44[7] = mat33[7];
197
198 matGL44[8] = 0;
199 matGL44[9] = 0;
200 matGL44[10] = 1.0;
201 matGL44[11] = 0.0;
202
203 matGL44[12] = mat33[2];
204 matGL44[13] = mat33[5];
205 matGL44[14] = 0.0;
206 matGL44[15] = mat33[8];
207}
208
mbansal1e762b12011-08-16 10:01:20 -0400209// This function computes fills the 4x4 matrices g_dAffinetrans,
mbansala6f0b9e2011-08-19 10:18:54 -0400210// and g_dAffinetransPan using the specified 3x3 affine
mbansal1e762b12011-08-16 10:01:20 -0400211// transformation between the first captured frame and the current frame.
mbansala6f0b9e2011-08-19 10:18:54 -0400212// The computed g_dAffinetrans is such that it warps the preview mosaic in
213// the last frame's coordinate system into the coordinate system of the
214// current frame. Thus, applying this transformation will create the current
215// frame mosaic but with the current frame missing. This frame will then be
216// pasted in by gWarper2 after translating it by g_dTranslationToFBOCenter.
217// The computed g_dAffinetransPan is such that it offsets the computed preview
218// mosaic horizontally to make the viewfinder pan within the UI layout.
mbansaleeb94d42011-08-02 11:31:28 -0400219void UpdateWarpTransformation(float *trs)
220{
mbansala6f0b9e2011-08-19 10:18:54 -0400221 double H[9], Hp[9], Htemp1[9], Htemp2[9], T[9];
mbansaleeb94d42011-08-02 11:31:28 -0400222
mbansala6f0b9e2011-08-19 10:18:54 -0400223 for(int i = 0; i < 9; i++)
mbansaleeb94d42011-08-02 11:31:28 -0400224 {
mbansala6f0b9e2011-08-19 10:18:54 -0400225 gThisH1t[i] = trs[i];
mbansaleeb94d42011-08-02 11:31:28 -0400226 }
227
mbansala6f0b9e2011-08-19 10:18:54 -0400228 db_Identity3x3(T);
229 T[2] = -gCenterOffsetX;
230 T[5] = -gCenterOffsetY;
231
232 // H = ( inv(gThisH1t) * gLastH1t ) * T
233 db_Identity3x3(Htemp1);
234 db_Identity3x3(Htemp2);
235 db_Identity3x3(H);
236 db_InvertAffineTransform(Htemp1, gThisH1t);
237 db_Multiply3x3_3x3(Htemp2, Htemp1, gLastH1t);
238 db_Multiply3x3_3x3(H, Htemp2, T);
239
240 for(int i = 0; i < 9; i++)
241 {
242 gLastH1t[i] = gThisH1t[i];
243 }
mbansal1e762b12011-08-16 10:01:20 -0400244
mbansaleeb94d42011-08-02 11:31:28 -0400245 // Move the origin such that the frame is centered in the previewFBO
mbansala6f0b9e2011-08-19 10:18:54 -0400246 // i.e. H = inv(T) * H
247 H[2] += gCenterOffsetX;
248 H[5] += gCenterOffsetY;
mbansaleeb94d42011-08-02 11:31:28 -0400249
250 // Hp = inv(K) * H * K
mbansal1e762b12011-08-16 10:01:20 -0400251 // K moves the coordinate system from openGL to image pixels so
252 // that the alignment transform H can be applied to them.
253 // inv(K) moves the coordinate system back to openGL normalized
254 // coordinates so that the shader can correctly render it.
mbansala6f0b9e2011-08-19 10:18:54 -0400255 db_Identity3x3(Htemp1);
256 db_Multiply3x3_3x3(Htemp1, H, gKm);
257 db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
mbansaleeb94d42011-08-02 11:31:28 -0400258
259 ConvertAffine3x3toGL4x4(g_dAffinetrans, Hp);
260
mbansala6f0b9e2011-08-19 10:18:54 -0400261 ////////////////////////////////////////////////
262 ////// Compute g_dAffinetransPan now... //////
263 ////////////////////////////////////////////////
mbansaleeb94d42011-08-02 11:31:28 -0400264
mbansala6f0b9e2011-08-19 10:18:54 -0400265 gThisTx = trs[2];
mbansaleeb94d42011-08-02 11:31:28 -0400266
mbansala6f0b9e2011-08-19 10:18:54 -0400267 if(gPanViewfinder)
268 {
269 gPanOffset += (gThisTx - gLastTx) * VIEWFINDER_PAN_FACTOR_HORZ;
270 }
mbansal1e762b12011-08-16 10:01:20 -0400271
272 gLastTx = gThisTx;
273
mbansala6f0b9e2011-08-19 10:18:54 -0400274 // Compute the position of the current frame in the screen coordinate system
275 // and stop the viewfinder panning if we hit the maximum border allowed for
276 // this UI layout
277 double normalizedXPositionOnScreenLeft = (2 *
278 (gCenterOffsetX + gPanOffset) / gPreviewFBOWidth - 1.0) *
279 gUILayoutScalingX;
280 double normalizedScreenLimitLeft = -1.0 + VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
mbansaleeb94d42011-08-02 11:31:28 -0400281
mbansala6f0b9e2011-08-19 10:18:54 -0400282 double normalizedXPositionOnScreenRight = (2 *
283 ((gCenterOffsetX + gPanOffset) + gPreviewImageWidth[LR]) /
284 gPreviewFBOWidth - 1.0) * gUILayoutScalingX;
285 double normalizedScreenLimitRight = 1.0 - VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
mbansal1e762b12011-08-16 10:01:20 -0400286
mbansala6f0b9e2011-08-19 10:18:54 -0400287 if(normalizedXPositionOnScreenRight > normalizedScreenLimitRight ||
288 normalizedXPositionOnScreenLeft < normalizedScreenLimitLeft)
289 gPanViewfinder = false;
mbansal1e762b12011-08-16 10:01:20 -0400290
mbansala6f0b9e2011-08-19 10:18:54 -0400291 db_Identity3x3(H);
292 H[2] = gPanOffset;
mbansaleeb94d42011-08-02 11:31:28 -0400293
mbansala6f0b9e2011-08-19 10:18:54 -0400294 // Hp = inv(K) * H * K
295 db_Identity3x3(Htemp1);
296 db_Multiply3x3_3x3(Htemp1, H, gKm);
297 db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
mbansaleeb94d42011-08-02 11:31:28 -0400298
mbansala6f0b9e2011-08-19 10:18:54 -0400299 ConvertAffine3x3toGL4x4(g_dAffinetransPan, Hp);
mbansaleeb94d42011-08-02 11:31:28 -0400300}
301
mbansal41a2e972011-08-08 20:23:02 -0400302void AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR)
mbansaleeb94d42011-08-02 11:31:28 -0400303{
mbansal1e762b12011-08-16 10:01:20 -0400304 gPreviewImageWidth[HR] = widthHR;
305 gPreviewImageHeight[HR] = heightHR;
mbansal41a2e972011-08-08 20:23:02 -0400306
mbansal1e762b12011-08-16 10:01:20 -0400307 gPreviewImageWidth[LR] = widthLR;
308 gPreviewImageHeight[LR] = heightLR;
mbansaleeb94d42011-08-02 11:31:28 -0400309
mbansal1e762b12011-08-16 10:01:20 -0400310 sem_init(&gPreviewImage_semaphore, 0, 1);
mbansaleeb94d42011-08-02 11:31:28 -0400311
mbansal1e762b12011-08-16 10:01:20 -0400312 sem_wait(&gPreviewImage_semaphore);
313 gPreviewImage[LR] = ImageUtils::allocateImage(gPreviewImageWidth[LR],
314 gPreviewImageHeight[LR], 4);
315 ClearPreviewImage(LR);
316 gPreviewImage[HR] = ImageUtils::allocateImage(gPreviewImageWidth[HR],
317 gPreviewImageHeight[HR], 4);
318 ClearPreviewImage(HR);
319 sem_post(&gPreviewImage_semaphore);
mbansaleeb94d42011-08-02 11:31:28 -0400320
mbansal1e762b12011-08-16 10:01:20 -0400321 gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR];
322 gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR];
mbansaleeb94d42011-08-02 11:31:28 -0400323
mbansala6f0b9e2011-08-19 10:18:54 -0400324 // The origin is such that the current frame will sit with its center
325 // at the center of the previewFBO
326 gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[LR] / 2);
327 gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[LR] / 2);
328
329 gPanOffset = 0.0f;
330
331 db_Identity3x3(gThisH1t);
332 db_Identity3x3(gLastH1t);
333
334 gPanViewfinder = true;
335
336 int w = gPreviewImageWidth[LR];
337 int h = gPreviewImageHeight[LR];
338
339 int wm = gPreviewFBOWidth;
340 int hm = gPreviewFBOHeight;
341
342 // K is the transformation to map the canonical [-1,1] vertex coordinate
343 // system to the [0,w] image coordinate system before applying the given
344 // affine transformation trs.
345 gKm[0] = wm / 2.0 - 0.5;
346 gKm[1] = 0.0;
347 gKm[2] = wm / 2.0 - 0.5;
348 gKm[3] = 0.0;
349 gKm[4] = hm / 2.0 - 0.5;
350 gKm[5] = hm / 2.0 - 0.5;
351 gKm[6] = 0.0;
352 gKm[7] = 0.0;
353 gKm[8] = 1.0;
354
355 gK[0] = w / 2.0 - 0.5;
356 gK[1] = 0.0;
357 gK[2] = w / 2.0 - 0.5;
358 gK[3] = 0.0;
359 gK[4] = h / 2.0 - 0.5;
360 gK[5] = h / 2.0 - 0.5;
361 gK[6] = 0.0;
362 gK[7] = 0.0;
363 gK[8] = 1.0;
364
365 db_Identity3x3(gKinv);
366 db_InvertCalibrationMatrix(gKinv, gK);
367
368 db_Identity3x3(gKminv);
369 db_InvertCalibrationMatrix(gKminv, gKm);
370
371 //////////////////////////////////////////
372 ////// Compute g_Translation now... //////
373 //////////////////////////////////////////
374 double T[9], Tp[9], Ttemp[9];
375
376 db_Identity3x3(T);
377 T[2] = gCenterOffsetX;
378 T[5] = gCenterOffsetY;
379
380 // Tp = inv(K) * T * K
381 db_Identity3x3(Ttemp);
382 db_Multiply3x3_3x3(Ttemp, T, gK);
383 db_Multiply3x3_3x3(Tp, gKinv, Ttemp);
384
385 ConvertAffine3x3toGL4x4(g_dTranslationToFBOCenter, Tp);
mbansal1e762b12011-08-16 10:01:20 -0400386
387 UpdateWarpTransformation(g_dIdent3x3);
mbansaleeb94d42011-08-02 11:31:28 -0400388}
389
390void FreeTextureMemory()
391{
mbansal1e762b12011-08-16 10:01:20 -0400392 sem_wait(&gPreviewImage_semaphore);
393 ImageUtils::freeImage(gPreviewImage[LR]);
394 ImageUtils::freeImage(gPreviewImage[HR]);
395 sem_post(&gPreviewImage_semaphore);
mbansaleeb94d42011-08-02 11:31:28 -0400396
mbansal1e762b12011-08-16 10:01:20 -0400397 sem_destroy(&gPreviewImage_semaphore);
mbansaleeb94d42011-08-02 11:31:28 -0400398}
399
400extern "C"
401{
mbansal41a2e972011-08-08 20:23:02 -0400402 JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
mbansaleeb94d42011-08-02 11:31:28 -0400403 JNIEnv * env, jobject obj);
404 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
405 JNIEnv * env, jobject obj, jint width, jint height);
mbansal41a2e972011-08-08 20:23:02 -0400406 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
407 JNIEnv * env, jobject obj, jfloatArray stMatrix);
408 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
409 JNIEnv * env, jobject obj);
mbansaleeb94d42011-08-02 11:31:28 -0400410 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
411 JNIEnv * env, jobject obj);
412 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
413 JNIEnv * env, jobject obj);
mbansal41a2e972011-08-08 20:23:02 -0400414 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
415 JNIEnv * env, jobject obj, jboolean flag);
mbansaleeb94d42011-08-02 11:31:28 -0400416};
417
mbansal41a2e972011-08-08 20:23:02 -0400418JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
mbansaleeb94d42011-08-02 11:31:28 -0400419 JNIEnv * env, jobject obj)
420{
mbansal41a2e972011-08-08 20:23:02 -0400421 gSurfTexRenderer[LR].InitializeGLProgram();
422 gSurfTexRenderer[HR].InitializeGLProgram();
mbansal1e762b12011-08-16 10:01:20 -0400423 gYVURenderer[LR].InitializeGLProgram();
424 gYVURenderer[HR].InitializeGLProgram();
425 gWarper1.InitializeGLProgram();
426 gWarper2.InitializeGLProgram();
mbansaleeb94d42011-08-02 11:31:28 -0400427 gPreview.InitializeGLProgram();
mbansal1e762b12011-08-16 10:01:20 -0400428 gBuffer[0].InitializeGLContext();
429 gBuffer[1].InitializeGLContext();
mbansal41a2e972011-08-08 20:23:02 -0400430 gBufferInput[LR].InitializeGLContext();
431 gBufferInput[HR].InitializeGLContext();
mbansal1e762b12011-08-16 10:01:20 -0400432 gBufferInputYVU[LR].InitializeGLContext();
433 gBufferInputYVU[HR].InitializeGLContext();
mbansaleeb94d42011-08-02 11:31:28 -0400434
435 glBindFramebuffer(GL_FRAMEBUFFER, 0);
mbansal41a2e972011-08-08 20:23:02 -0400436
437 glGenTextures(1, gSurfaceTextureID);
438 // bind the surface texture
439 bindSurfaceTexture(gSurfaceTextureID[0]);
440
441 return (jint) gSurfaceTextureID[0];
mbansaleeb94d42011-08-02 11:31:28 -0400442}
443
mbansal41a2e972011-08-08 20:23:02 -0400444
mbansaleeb94d42011-08-02 11:31:28 -0400445JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
446 JNIEnv * env, jobject obj, jint width, jint height)
447{
mbansala6f0b9e2011-08-19 10:18:54 -0400448 gUILayoutScalingX = (PREVIEW_FBO_WIDTH_SCALE / PREVIEW_FBO_HEIGHT_SCALE) *
449 (gPreviewImageWidth[LR] / gPreviewImageHeight[LR]) / (width / height) *
450 PREVIEW_FBO_HEIGHT_SCALE;
451 gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE;
452
mbansal1e762b12011-08-16 10:01:20 -0400453 gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
454 gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
mbansal41a2e972011-08-08 20:23:02 -0400455
mbansal1e762b12011-08-16 10:01:20 -0400456 gBufferInput[LR].Init(gPreviewImageWidth[LR],
457 gPreviewImageHeight[LR], GL_RGBA);
mbansal41a2e972011-08-08 20:23:02 -0400458
mbansal1e762b12011-08-16 10:01:20 -0400459 gBufferInput[HR].Init(gPreviewImageWidth[HR],
460 gPreviewImageHeight[HR], GL_RGBA);
mbansaleeb94d42011-08-02 11:31:28 -0400461
mbansal1e762b12011-08-16 10:01:20 -0400462 gBufferInputYVU[LR].Init(gPreviewImageWidth[LR],
463 gPreviewImageHeight[LR], GL_RGBA);
464
465 gBufferInputYVU[HR].Init(gPreviewImageWidth[HR],
466 gPreviewImageHeight[HR], GL_RGBA);
467
468 sem_wait(&gPreviewImage_semaphore);
469 ClearPreviewImage(LR);
470 ClearPreviewImage(HR);
471 sem_post(&gPreviewImage_semaphore);
mbansaleeb94d42011-08-02 11:31:28 -0400472
mbansal41a2e972011-08-08 20:23:02 -0400473 // bind the surface texture
474 bindSurfaceTexture(gSurfaceTextureID[0]);
mbansaleeb94d42011-08-02 11:31:28 -0400475
mbansal41a2e972011-08-08 20:23:02 -0400476 gSurfTexRenderer[LR].SetupGraphics(&gBufferInput[LR]);
477 gSurfTexRenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
478 gSurfTexRenderer[LR].SetViewportMatrix(1, 1, 1, 1);
479 gSurfTexRenderer[LR].SetScalingMatrix(1.0f, -1.0f);
480 gSurfTexRenderer[LR].SetInputTextureName(gSurfaceTextureID[0]);
481 gSurfTexRenderer[LR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
482
483 gSurfTexRenderer[HR].SetupGraphics(&gBufferInput[HR]);
484 gSurfTexRenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
485 gSurfTexRenderer[HR].SetViewportMatrix(1, 1, 1, 1);
486 gSurfTexRenderer[HR].SetScalingMatrix(1.0f, -1.0f);
487 gSurfTexRenderer[HR].SetInputTextureName(gSurfaceTextureID[0]);
488 gSurfTexRenderer[HR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
489
mbansal1e762b12011-08-16 10:01:20 -0400490 gYVURenderer[LR].SetupGraphics(&gBufferInputYVU[LR]);
491 gYVURenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
492 gYVURenderer[LR].SetInputTextureName(gBufferInput[LR].GetTextureName());
493 gYVURenderer[LR].SetInputTextureType(GL_TEXTURE_2D);
494
495 gYVURenderer[HR].SetupGraphics(&gBufferInputYVU[HR]);
496 gYVURenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
497 gYVURenderer[HR].SetInputTextureName(gBufferInput[HR].GetTextureName());
498 gYVURenderer[HR].SetInputTextureType(GL_TEXTURE_2D);
499
mbansala6f0b9e2011-08-19 10:18:54 -0400500 // gBuffer[1-gCurrentFBOIndex] --> gWarper1 --> gBuffer[gCurrentFBOIndex]
mbansal1e762b12011-08-16 10:01:20 -0400501 gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
502 gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
mbansala6f0b9e2011-08-19 10:18:54 -0400503 gWarper1.SetViewportMatrix(1, 1, 1, 1);
mbansal1e762b12011-08-16 10:01:20 -0400504 gWarper1.SetScalingMatrix(1.0f, 1.0f);
mbansala6f0b9e2011-08-19 10:18:54 -0400505 gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName());
mbansal1e762b12011-08-16 10:01:20 -0400506 gWarper1.SetInputTextureType(GL_TEXTURE_2D);
507
mbansala6f0b9e2011-08-19 10:18:54 -0400508 // gBufferInput[LR] --> gWarper2 --> gBuffer[gCurrentFBOIndex]
509 gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
mbansal1e762b12011-08-16 10:01:20 -0400510 gWarper2.Clear(0.0, 0.0, 0.0, 1.0);
mbansala6f0b9e2011-08-19 10:18:54 -0400511 gWarper2.SetViewportMatrix(gPreviewImageWidth[LR],
512 gPreviewImageHeight[LR], gBuffer[gCurrentFBOIndex].GetWidth(),
513 gBuffer[gCurrentFBOIndex].GetHeight());
mbansal1e762b12011-08-16 10:01:20 -0400514 gWarper2.SetScalingMatrix(1.0f, 1.0f);
mbansala6f0b9e2011-08-19 10:18:54 -0400515 gWarper2.SetInputTextureName(gBufferInput[LR].GetTextureName());
mbansal1e762b12011-08-16 10:01:20 -0400516 gWarper2.SetInputTextureType(GL_TEXTURE_2D);
mbansaleeb94d42011-08-02 11:31:28 -0400517
518 gPreview.SetupGraphics(width, height);
519 gPreview.Clear(0.0, 0.0, 0.0, 1.0);
520 gPreview.SetViewportMatrix(1, 1, 1, 1);
mbansal1e762b12011-08-16 10:01:20 -0400521 // Scale the previewFBO so that the viewfinder window fills the layout height
522 // while maintaining the image aspect ratio
mbansala6f0b9e2011-08-19 10:18:54 -0400523 gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY);
524 gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
mbansal41a2e972011-08-08 20:23:02 -0400525 gPreview.SetInputTextureType(GL_TEXTURE_2D);
526}
527
528JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
529 JNIEnv * env, jobject obj, jfloatArray stMatrix)
530{
531 jfloat *stmat = env->GetFloatArrayElements(stMatrix, 0);
532
533 gSurfTexRenderer[LR].SetSTMatrix((float*) stmat);
534 gSurfTexRenderer[HR].SetSTMatrix((float*) stmat);
535
536 env->ReleaseFloatArrayElements(stMatrix, stmat, 0);
537
538 gSurfTexRenderer[LR].DrawTexture(g_dAffinetransIdent);
539 gSurfTexRenderer[HR].DrawTexture(g_dAffinetransIdent);
540}
541
mbansal1e762b12011-08-16 10:01:20 -0400542#ifndef now_ms
543#include <time.h>
544static double
545now_ms(void)
546{
547 //struct timespec res;
548 struct timeval res;
549 //clock_gettime(CLOCK_REALTIME, &res);
550 gettimeofday(&res, NULL);
551 return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
552}
553#endif
554
555
556
mbansal41a2e972011-08-08 20:23:02 -0400557JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
558 JNIEnv * env, jobject obj)
559{
mbansal1e762b12011-08-16 10:01:20 -0400560 double t0, t1, time_c;
561
562 t0 = now_ms();
563
564 gYVURenderer[LR].DrawTexture();
565 gYVURenderer[HR].DrawTexture();
566
567 t1 = now_ms();
568 time_c = t1 - t0;
569 LOGV("YVU Rendering: %g ms", time_c);
570
571 sem_wait(&gPreviewImage_semaphore);
mbansal41a2e972011-08-08 20:23:02 -0400572 // Bind to the input LR FBO and read the Low-Res data from there...
mbansal1e762b12011-08-16 10:01:20 -0400573 glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[LR].GetFrameBufferName());
574 t0 = now_ms();
mbansal41a2e972011-08-08 20:23:02 -0400575 glReadPixels(0,
576 0,
577 gBufferInput[LR].GetWidth(),
578 gBufferInput[LR].GetHeight(),
579 GL_RGBA,
580 GL_UNSIGNED_BYTE,
mbansal1e762b12011-08-16 10:01:20 -0400581 gPreviewImage[LR]);
mbansal41a2e972011-08-08 20:23:02 -0400582
583 checkGlError("glReadPixels LR");
mbansal1e762b12011-08-16 10:01:20 -0400584 t1 = now_ms();
585 time_c = t1 - t0;
586 LOGV("glReadPixels LR: %g ms", time_c);
mbansal41a2e972011-08-08 20:23:02 -0400587
588 // Bind to the input HR FBO and read the high-res data from there...
mbansal1e762b12011-08-16 10:01:20 -0400589 glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[HR].GetFrameBufferName());
590 t0 = now_ms();
mbansal41a2e972011-08-08 20:23:02 -0400591 glReadPixels(0,
592 0,
593 gBufferInput[HR].GetWidth(),
594 gBufferInput[HR].GetHeight(),
595 GL_RGBA,
596 GL_UNSIGNED_BYTE,
mbansal1e762b12011-08-16 10:01:20 -0400597 gPreviewImage[HR]);
mbansal41a2e972011-08-08 20:23:02 -0400598
599 checkGlError("glReadPixels HR");
mbansal1e762b12011-08-16 10:01:20 -0400600 t1 = now_ms();
601 time_c = t1 - t0;
602 LOGV("glReadPixels HR: %g ms", time_c);
mbansal41a2e972011-08-08 20:23:02 -0400603
mbansal1e762b12011-08-16 10:01:20 -0400604 sem_post(&gPreviewImage_semaphore);
mbansaleeb94d42011-08-02 11:31:28 -0400605}
606
607JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
608 JNIEnv * env, jobject obj)
609{
mbansala6f0b9e2011-08-19 10:18:54 -0400610 if(!gWarpImage) // ViewFinder
mbansal1e762b12011-08-16 10:01:20 -0400611 {
mbansala6f0b9e2011-08-19 10:18:54 -0400612 gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
mbansal1e762b12011-08-16 10:01:20 -0400613 gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
mbansaleeb94d42011-08-02 11:31:28 -0400614
mbansala6f0b9e2011-08-19 10:18:54 -0400615 gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
616 gPreview.DrawTexture(g_dAffinetransIdent);
mbansal1e762b12011-08-16 10:01:20 -0400617 }
618 else
619 {
620 gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
mbansala6f0b9e2011-08-19 10:18:54 -0400621 // Clear the destination so that we can paint on it afresh
622 gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
623 gWarper1.SetInputTextureName(
624 gBuffer[1 - gCurrentFBOIndex].GetTextureName());
625 gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
626 gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
mbansal1e762b12011-08-16 10:01:20 -0400627
mbansal1e762b12011-08-16 10:01:20 -0400628 gWarper1.DrawTexture(g_dAffinetransGL);
mbansala6f0b9e2011-08-19 10:18:54 -0400629 gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
630 gPreview.DrawTexture(g_dAffinetransPanGL);
mbansal1e762b12011-08-16 10:01:20 -0400631
632 gCurrentFBOIndex = 1 - gCurrentFBOIndex;
633 }
mbansaleeb94d42011-08-02 11:31:28 -0400634}
635
mbansal41a2e972011-08-08 20:23:02 -0400636JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
637 JNIEnv * env, jobject obj, jboolean flag)
mbansaleeb94d42011-08-02 11:31:28 -0400638{
mbansal41a2e972011-08-08 20:23:02 -0400639 // TODO: Review this logic
640 if(gWarpImage != (bool) flag) //switching from viewfinder to capture or vice-versa
641 {
mbansala6f0b9e2011-08-19 10:18:54 -0400642 // Clear gBuffer[0]
643 gWarper1.SetupGraphics(&gBuffer[0]);
mbansal1e762b12011-08-16 10:01:20 -0400644 gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
mbansala6f0b9e2011-08-19 10:18:54 -0400645 // Clear gBuffer[1]
646 gWarper1.SetupGraphics(&gBuffer[1]);
647 gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
mbansal41a2e972011-08-08 20:23:02 -0400648 // Clear the screen to black.
mbansala6f0b9e2011-08-19 10:18:54 -0400649 gPreview.Clear(0.0, 0.0, 0.0, 1.0);
650
651 gLastTx = 0.0f;
652 gPanOffset = 0.0f;
653 gPanViewfinder = true;
654
655 db_Identity3x3(gThisH1t);
656 db_Identity3x3(gLastH1t);
mbansal41a2e972011-08-08 20:23:02 -0400657 }
mbansala6f0b9e2011-08-19 10:18:54 -0400658
mbansal41a2e972011-08-08 20:23:02 -0400659 gWarpImage = (bool)flag;
mbansaleeb94d42011-08-02 11:31:28 -0400660}
661
662
663JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
664 JNIEnv * env, jobject obj)
665{
mbansaleeb94d42011-08-02 11:31:28 -0400666 for(int i=0; i<16; i++)
667 {
668 g_dAffinetransGL[i] = g_dAffinetrans[i];
mbansala6f0b9e2011-08-19 10:18:54 -0400669 g_dAffinetransPanGL[i] = g_dAffinetransPan[i];
670 g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i];
mbansaleeb94d42011-08-02 11:31:28 -0400671 }
672}