nuclear@6: #include nuclear@9: #include nuclear@6: #include nuclear@6: #include nuclear@6: #include "opengl.h" nuclear@6: #include "camera.h" nuclear@25: #include "sdr.h" nuclear@25: #include "sanegl.h" nuclear@6: nuclear@6: nuclear@6: static JavaVM *jvm; nuclear@6: static JNIEnv *jni; nuclear@6: static jclass activity_class; nuclear@6: static unsigned int tex; nuclear@9: static float tex_matrix[16]; nuclear@9: static const float identity_matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@9: static jfloatArray jtex_matrix; nuclear@6: static int capturing; nuclear@6: nuclear@25: static unsigned int sdr_cam; nuclear@25: static int aloc_vertex, aloc_texcoord; nuclear@25: nuclear@25: nuclear@6: int cam_init(void *platform_data) nuclear@6: { nuclear@6: int glerr; nuclear@6: struct cam_android_platform_data *pdata = platform_data; nuclear@6: nuclear@6: jvm = pdata->vm; nuclear@6: jni = pdata->jni; nuclear@6: activity_class = pdata->activity_class; nuclear@6: nuclear@9: jtex_matrix = (*jni)->NewFloatArray(jni, 16); nuclear@9: nuclear@25: // load preview shader nuclear@25: if(!(sdr_cam = create_program_load("sdr/vertex.glsl", "sdr/android_cam_preview.p.glsl"))) { nuclear@25: return -1; nuclear@25: } nuclear@25: aloc_vertex = glGetAttribLocation(sdr_cam, "attr_vertex"); nuclear@25: aloc_texcoord = glGetAttribLocation(sdr_cam, "attr_texcoord"); nuclear@25: nuclear@6: // create the camera texture nuclear@6: assert(glGetError() == GL_NO_ERROR); nuclear@6: glGenTextures(1, &tex); nuclear@6: glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); nuclear@6: glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); nuclear@6: glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nuclear@6: nuclear@6: glerr = glGetError(); nuclear@6: assert(glerr == GL_NO_ERROR); nuclear@6: return glerr == GL_NO_ERROR ? 0 : -1; nuclear@6: } nuclear@6: nuclear@6: void cam_shutdown(void) nuclear@6: { nuclear@6: cam_stop_video(); nuclear@6: glDeleteTextures(1, &tex); nuclear@6: tex = 0; nuclear@9: nuclear@25: free_program(sdr_cam); nuclear@25: nuclear@9: if(jni) { nuclear@9: (*jni)->DeleteGlobalRef(jni, jtex_matrix); nuclear@9: } nuclear@6: } nuclear@6: nuclear@6: unsigned int cam_texture(void) nuclear@6: { nuclear@6: return tex; nuclear@6: } nuclear@6: nuclear@9: const float *cam_texture_matrix(void) nuclear@6: { nuclear@9: return tex_matrix; nuclear@6: } nuclear@6: nuclear@6: int cam_start_video(void) nuclear@6: { nuclear@6: jmethodID method; nuclear@6: nuclear@6: if(!jvm) { nuclear@6: fprintf(stderr, "failed to start video, camera not initialized\n"); nuclear@6: return -1; nuclear@6: } nuclear@6: if(cam_is_capturing()) { nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@6: if(!(method = (*jni)->GetStaticMethodID(jni, activity_class, "start_video", "(I)I"))) { nuclear@6: fprintf(stderr, "failed to find static method: start_video\n"); nuclear@6: return -1; nuclear@6: } nuclear@6: if((*jni)->CallStaticIntMethod(jni, activity_class, method, tex) == -1) { nuclear@6: fprintf(stderr, "failed to start video capture\n"); nuclear@6: capturing = 0; nuclear@6: return -1; nuclear@6: } nuclear@6: capturing = 1; nuclear@6: nuclear@6: printf("video started\n"); nuclear@6: nuclear@6: return 1; nuclear@6: } nuclear@6: nuclear@6: int cam_stop_video(void) nuclear@6: { nuclear@6: jmethodID method; nuclear@6: nuclear@6: if(!jvm) { nuclear@6: fprintf(stderr, "failed to stop video, camera not initialized\n"); nuclear@6: return -1; nuclear@6: } nuclear@6: nuclear@6: if(!cam_is_capturing()) { nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@6: if(!(method = (*jni)->GetStaticMethodID(jni, activity_class, "stop_video", "()V"))) { nuclear@6: fprintf(stderr, "failed to find static method: stop_video\n"); nuclear@6: return -1; nuclear@6: } nuclear@6: (*jni)->CallStaticVoidMethod(jni, activity_class, method); nuclear@6: capturing = 0; nuclear@6: nuclear@6: printf("video stopped\n"); nuclear@6: nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@8: int cam_update(void) nuclear@7: { nuclear@9: static int texmat_fail_warned; nuclear@7: jmethodID method; nuclear@9: float *ptr; nuclear@7: nuclear@7: if(!jvm) { nuclear@7: fprintf(stderr, "failed to update camera\n"); nuclear@7: return -1; nuclear@7: } nuclear@7: if(!cam_is_capturing()) { nuclear@7: return 0; nuclear@7: } nuclear@7: nuclear@9: if(!(method = (*jni)->GetStaticMethodID(jni, activity_class, "update", "([F)V"))) { nuclear@7: fprintf(stderr, "failed to find static method: update\n"); nuclear@7: return -1; nuclear@7: } nuclear@9: (*jni)->CallStaticVoidMethod(jni, activity_class, method, jtex_matrix); nuclear@9: nuclear@9: if(!(ptr = (*jni)->GetFloatArrayElements(jni, jtex_matrix, 0))) { nuclear@9: if(!texmat_fail_warned) { nuclear@9: fprintf(stderr, "failed to get texture matrix\n"); nuclear@9: texmat_fail_warned = 1; nuclear@9: } nuclear@9: memcpy(tex_matrix, identity_matrix, sizeof identity_matrix); nuclear@9: } else { nuclear@9: memcpy(tex_matrix, ptr, 16 * sizeof *ptr); nuclear@9: (*jni)->ReleaseFloatArrayElements(jni, jtex_matrix, ptr, JNI_ABORT); nuclear@9: } nuclear@9: nuclear@8: return 0; nuclear@7: } nuclear@7: nuclear@6: int cam_is_capturing(void) nuclear@6: { nuclear@6: return capturing; // XXX is it better to do this properly through JNI? nuclear@6: } nuclear@6: nuclear@9: int cam_video_size(int *xsz, int *ysz) nuclear@9: { nuclear@9: jfieldID jwidth, jheight; nuclear@9: nuclear@9: if(!(jwidth = (*jni)->GetStaticFieldID(jni, activity_class, "preview_width", "I")) || nuclear@9: !(jheight = (*jni)->GetStaticFieldID(jni, activity_class, "preview_height", "I"))) { nuclear@9: fprintf(stderr, "failed to retrieve preview width/height fields\n"); nuclear@9: *xsz = *ysz = 0; nuclear@9: return -1; nuclear@9: } nuclear@9: nuclear@9: *xsz = (*jni)->GetStaticIntField(jni, activity_class, jwidth); nuclear@9: *ysz = (*jni)->GetStaticIntField(jni, activity_class, jheight); nuclear@9: return 0; nuclear@9: } nuclear@9: nuclear@6: int cam_take_picture(void) nuclear@6: { nuclear@6: return -1; // TODO nuclear@6: } nuclear@25: nuclear@25: void cam_draw_preview(void) nuclear@25: { nuclear@25: const float *tex_matrix = cam_texture_matrix(); nuclear@25: nuclear@25: gl_matrix_mode(GL_TEXTURE); nuclear@25: gl_load_matrixf(tex_matrix); nuclear@25: nuclear@25: glUseProgram(sdr_cam); nuclear@25: glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); nuclear@25: nuclear@25: gl_begin(GL_QUADS); nuclear@25: gl_texcoord2f(0, 0); nuclear@25: gl_vertex2f(-1, -1); nuclear@25: gl_texcoord2f(1, 0); nuclear@25: gl_vertex2f(1, -1); nuclear@25: gl_texcoord2f(1, 1); nuclear@25: gl_vertex2f(1, 1); nuclear@25: gl_texcoord2f(0, 1); nuclear@25: gl_vertex2f(-1, 1); nuclear@25: gl_end(); nuclear@25: nuclear@25: gl_matrix_mode(GL_TEXTURE); nuclear@25: gl_load_identity(); nuclear@25: }