jboolean Java_android_filterfw_core_GLFrame_setNativeBitmap(JNIEnv* env,
                                                            jobject thiz,
                                                            jobject bitmap,
                                                            jint size) {
  GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
  if (frame && bitmap) {
    uint8_t* pixels;
    const int result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void**>(&pixels));
    if (result == ANDROID_BITMAP_RESUT_SUCCESS) {
      const bool success = frame->WriteData(pixels, size);
      return ToJBool(success &&
                     AndroidBitmap_unlockPixels(env, bitmap) == ANDROID_BITMAP_RESUT_SUCCESS);
    }
  }
  return JNI_FALSE;
}
jboolean Java_android_filterfw_core_GLFrame_setNativeInts(JNIEnv* env,
                                                          jobject thiz,
                                                          jintArray ints) {
  GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
  if (frame && ints) {
    jint* int_ptr = env->GetIntArrayElements(ints, NULL);
    const int length = env->GetArrayLength(ints);
    if (int_ptr) {
      const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(int_ptr),
                                            length * sizeof(jint));
      env->ReleaseIntArrayElements(ints, int_ptr, JNI_ABORT);
      return ToJBool(success);
    }
  }
  return JNI_FALSE;
}
jboolean Java_android_filterfw_core_GLFrame_setNativeData(JNIEnv* env,
                                                          jobject thiz,
                                                          jbyteArray data,
                                                          jint offset,
                                                          jint length) {
  GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
  if (frame && data) {
    jbyte* bytes = env->GetByteArrayElements(data, NULL);
    if (bytes) {
      const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(bytes + offset), length);
      env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
      return ToJBool(success);
    }
  }
  return JNI_FALSE;
}
jboolean Java_android_filterfw_core_GLFrame_setNativeFloats(JNIEnv* env,
                                                            jobject thiz,
                                                            jfloatArray floats) {
  GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
  if (frame && floats) {
    jfloat* float_ptr = env->GetFloatArrayElements(floats, NULL);
    const int length = env->GetArrayLength(floats);
    if (float_ptr) {
      // Convert floats to RGBA buffer
      uint8_t* rgba_buffer = new uint8_t[length];
      ConvertFloatsToRGBA(float_ptr, length, rgba_buffer);
      env->ReleaseFloatArrayElements(floats, float_ptr, JNI_ABORT);

      // Write RGBA buffer to frame
      const bool success = frame->WriteData(rgba_buffer, length);

      // Clean-up
      delete[] rgba_buffer;
      return ToJBool(success);
    }
  }
  return JNI_FALSE;
}