1/*
2 * Copyright 2021 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <android/log.h>
9#include <jni.h>
10
11#include "include/core/SkM44.h"
12#include "include/effects/SkRuntimeEffect.h"
13#include "modules/androidkit/src/Utils.h"
14
15namespace {
16
17static jlong ShaderBuilder_Create(JNIEnv* env, jobject, jstring jsksl) {
18    auto [eff,err] = SkRuntimeEffect::MakeForShader(
19                         SkString(androidkit::utils::CString(env, jsksl)));
20
21    if (!eff) {
22        // TODO: throw exception?
23        __android_log_print(ANDROID_LOG_ERROR, "AndroidKit", "Failed to compile shader: %s\n",
24                            err.c_str());
25        return 0;
26    }
27
28    return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(eff)));
29}
30
31static void ShaderBuilder_Release(JNIEnv* env, jobject, jlong native_instance) {
32    if (auto* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(native_instance)) {
33        delete builder;
34    }
35}
36
37static void ShaderBuilder_SetUniformFloat(JNIEnv* env, jobject, jlong native_instance, jstring jname, float val) {
38    if (auto* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(native_instance)) {
39        builder->uniform(androidkit::utils::CString(env, jname)) = val;
40    }
41}
42
43static void ShaderBuilder_SetUniformFloat3(JNIEnv* env, jobject, jlong native_instance, jstring jname, float valX, float valY, float valZ) {
44    if (auto* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(native_instance)) {
45        builder->uniform(androidkit::utils::CString(env, jname)) = SkV3{valX, valY, valZ};
46    }
47}
48
49static void ShaderBuilder_SetUniformMatrix(JNIEnv* env, jobject, jlong native_instance, jstring jname, jlong native_matrix) {
50    if (auto* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(native_instance)) {
51        if (auto* matrix = reinterpret_cast<SkM44*>(native_matrix)) {
52            builder->uniform(androidkit::utils::CString(env, jname)) = *matrix;
53        }
54    }
55}
56
57static jlong ShaderBuilder_MakeShader(JNIEnv* env, jobject, jlong native_instance) {
58    if (auto* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(native_instance)) {
59        auto shader = builder->makeShader(nullptr, false);
60        return reinterpret_cast<jlong>(shader.release());
61    }
62
63    return 0;
64}
65
66}  // namespace
67
68int register_androidkit_RuntimeShaderBuilder(JNIEnv* env) {
69    static const JNINativeMethod methods[] = {
70        {"nCreate"          , "(Ljava/lang/String;)J"       , reinterpret_cast<void*>(ShaderBuilder_Create)},
71        {"nRelease"         , "(J)V"                        , reinterpret_cast<void*>(ShaderBuilder_Release)},
72
73        {"nSetUniformFloat" , "(JLjava/lang/String;F)V"     , reinterpret_cast<void*>(ShaderBuilder_SetUniformFloat)},
74        {"nSetUniformFloat3", "(JLjava/lang/String;FFF)V"   , reinterpret_cast<void*>(ShaderBuilder_SetUniformFloat3)},
75        {"nSetUniformMatrix", "(JLjava/lang/String;J)V"     , reinterpret_cast<void*>(ShaderBuilder_SetUniformMatrix)},
76        {"nMakeShader"      , "(J)J"                        , reinterpret_cast<void*>(ShaderBuilder_MakeShader)},
77    };
78
79    const auto clazz = env->FindClass("org/skia/androidkit/RuntimeShaderBuilder");
80    return clazz
81        ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
82        : JNI_ERR;
83}
84