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 <string>
18#include <vector>
19
20#include "jni/jni_shader_program.h"
21#include "jni/jni_util.h"
22
23#include "native/base/logging.h"
24#include "native/core/geometry.h"
25#include "native/core/gl_env.h"
26#include "native/core/gl_frame.h"
27#include "native/core/shader_program.h"
28#include "native/core/vertex_frame.h"
29
30using android::filterfw::GLEnv;
31using android::filterfw::GLFrame;
32using android::filterfw::Point;
33using android::filterfw::ProgramVar;
34using android::filterfw::Quad;
35using android::filterfw::ShaderProgram;
36using android::filterfw::VertexFrame;
37
38jboolean Java_android_filterfw_core_ShaderProgram_allocate(JNIEnv* env,
39                                                           jobject thiz,
40                                                           jobject gl_env,
41                                                           jstring vertex_shader,
42                                                           jstring fragment_shader) {
43  // Get the GLEnv pointer
44  GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
45
46  // Create the shader
47  if (!fragment_shader || !gl_env_ptr)
48    return false;
49  else if (!vertex_shader)
50    return ToJBool(WrapObjectInJava(new ShaderProgram(
51      gl_env_ptr,
52      ToCppString(env, fragment_shader)),
53      env,
54      thiz,
55      true));
56  else
57    return ToJBool(WrapObjectInJava(new ShaderProgram(
58      gl_env_ptr,
59      ToCppString(env, vertex_shader),
60      ToCppString(env, fragment_shader)),
61      env,
62      thiz,
63      true));
64}
65
66jboolean Java_android_filterfw_core_ShaderProgram_deallocate(JNIEnv* env, jobject thiz) {
67  return ToJBool(DeleteNativeObject<ShaderProgram>(env, thiz));
68}
69
70jboolean Java_android_filterfw_core_ShaderProgram_compileAndLink(JNIEnv* env, jobject thiz) {
71  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
72  return program ? ToJBool(program->CompileAndLink()) : JNI_FALSE;
73}
74
75jboolean Java_android_filterfw_core_ShaderProgram_setUniformValue(JNIEnv* env,
76                                                                  jobject thiz,
77                                                                  jstring key,
78                                                                  jobject value) {
79  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
80  const Value c_value = ToCValue(env, value);
81  const std::string c_key = ToCppString(env, key);
82  if (c_value.value) {
83    return ToJBool(program && program->SetUniformValue(c_key, c_value));
84  } else {
85    ALOGE("ShaderProgram: Could not convert java object value passed for key '%s'!", c_key.c_str());
86    return JNI_FALSE;
87  }
88}
89
90jobject Java_android_filterfw_core_ShaderProgram_getUniformValue(JNIEnv* env,
91                                                                 jobject thiz,
92                                                                 jstring key) {
93  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
94  const std::string c_key = ToCppString(env, key);
95  return program ? ToJObject(env, program->GetUniformValue(c_key)) : JNI_NULL;
96}
97
98jboolean Java_android_filterfw_core_ShaderProgram_shaderProcess(JNIEnv* env,
99                                                                jobject thiz,
100                                                                jobjectArray inputs,
101                                                                jobject output) {
102  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
103  std::vector<const GLFrame*> input_frames;
104  if (program && inputs && output) {
105    // Get the input frames
106    const int input_count = env->GetArrayLength(inputs);
107    for (int i = 0; i < input_count; ++i) {
108      jobject input = env->GetObjectArrayElement(inputs, i);
109      const GLFrame* input_frame = ConvertFromJava<GLFrame>(env, input);
110      if (!input || !input_frame) {
111        ALOGE("ShaderProgram: invalid input frame %d!", i);
112        return JNI_FALSE;
113      }
114      input_frames.push_back(input_frame);
115    }
116
117    // Get the output frame
118    GLFrame* output_frame = ConvertFromJava<GLFrame>(env, output);
119    if (!output_frame) {
120      ALOGE("ShaderProgram: no output frame found!");
121      return JNI_FALSE;
122    }
123
124    // Process the frames!
125    if (!program->Process(input_frames, output_frame)) {
126      ALOGE("ShaderProgram: error processing shader!");
127      return JNI_FALSE;
128    }
129
130    return JNI_TRUE;
131  }
132  return JNI_FALSE;
133}
134
135jobject Java_android_filterfw_core_ShaderProgram_nativeCreateIdentity(JNIEnv* env,
136                                                                      jclass,
137                                                                      jobject gl_env) {
138  GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env);
139  ShaderProgram* program = gl_env_ptr ? ShaderProgram::CreateIdentity(gl_env_ptr) : NULL;
140  return program ? WrapNewObjectInJava(program, env, false) : NULL;
141}
142
143jboolean Java_android_filterfw_core_ShaderProgram_setSourceRegion(JNIEnv* env,
144                                                                  jobject thiz,
145                                                                  jfloat x0,
146                                                                  jfloat y0,
147                                                                  jfloat x1,
148                                                                  jfloat y1,
149                                                                  jfloat x2,
150                                                                  jfloat y2,
151                                                                  jfloat x3,
152                                                                  jfloat y3) {
153  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
154  if (program) {
155    program->SetSourceRegion(Quad(Point(x0, y0), Point(x1, y1), Point(x2, y2), Point(x3, y3)));
156    return JNI_TRUE;
157  }
158  return JNI_FALSE;
159}
160
161jboolean Java_android_filterfw_core_ShaderProgram_setTargetRegion(JNIEnv* env,
162                                                                  jobject thiz,
163                                                                  jfloat x0,
164                                                                  jfloat y0,
165                                                                  jfloat x1,
166                                                                  jfloat y1,
167                                                                  jfloat x2,
168                                                                  jfloat y2,
169                                                                  jfloat x3,
170                                                                  jfloat y3) {
171  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
172  if (program) {
173    program->SetTargetRegion(Quad(Point(x0, y0), Point(x1, y1), Point(x2, y2), Point(x3, y3)));
174    return JNI_TRUE;
175  }
176  return JNI_FALSE;
177}
178
179jboolean Java_android_filterfw_core_ShaderProgram_setShaderClearsOutput(JNIEnv* env,
180                                                                        jobject thiz,
181                                                                        jboolean clears) {
182  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
183  if (program) {
184    program->SetClearsOutput(ToCppBool(clears));
185    return JNI_TRUE;
186  }
187  return JNI_FALSE;
188}
189
190jboolean Java_android_filterfw_core_ShaderProgram_setShaderBlendEnabled(JNIEnv* env,
191                                                                        jobject thiz,
192                                                                        jboolean enable) {
193  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
194  if (program) {
195    program->SetBlendEnabled(ToCppBool(enable));
196    return JNI_TRUE;
197  }
198  return JNI_FALSE;
199}
200
201jboolean Java_android_filterfw_core_ShaderProgram_setShaderBlendFunc(JNIEnv* env,
202                                                                     jobject thiz,
203                                                                     jint sfactor,
204                                                                     jint dfactor) {
205  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
206  if (program) {
207    program->SetBlendFunc(sfactor, dfactor);
208    return JNI_TRUE;
209  }
210  return JNI_FALSE;
211}
212
213jboolean Java_android_filterfw_core_ShaderProgram_setShaderClearColor(JNIEnv* env,
214                                                                      jobject thiz,
215                                                                      jfloat r,
216                                                                      jfloat g,
217                                                                      jfloat b) {
218  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
219  if (program) {
220    program->SetClearColor(r, g, b, 1.0f);
221    return JNI_TRUE;
222  }
223  return JNI_FALSE;
224}
225
226jboolean Java_android_filterfw_core_ShaderProgram_setShaderDrawMode(JNIEnv* env,
227                                                                    jobject thiz,
228                                                                    jint draw_mode) {
229  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
230  if (program) {
231    program->SetDrawMode(draw_mode);
232    return JNI_TRUE;
233  }
234  return JNI_FALSE;
235}
236
237jboolean Java_android_filterfw_core_ShaderProgram_setShaderTileCounts(JNIEnv* env,
238                                                                      jobject thiz,
239                                                                      jint x_count,
240                                                                      jint y_count) {
241  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
242  if (program) {
243    program->SetTileCounts(x_count, y_count);
244    return JNI_TRUE;
245  }
246  return JNI_FALSE;
247}
248
249jboolean Java_android_filterfw_core_ShaderProgram_setShaderVertexCount(JNIEnv* env,
250                                                                       jobject thiz,
251                                                                       jint vertex_count) {
252  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
253  if (program) {
254    program->SetVertexCount(vertex_count);
255    return JNI_TRUE;
256  }
257  return JNI_FALSE;
258}
259
260jboolean Java_android_filterfw_core_ShaderProgram_beginShaderDrawing(JNIEnv* env, jobject thiz) {
261    ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
262    return ToJBool(program && program->BeginDraw());
263}
264
265jboolean Java_android_filterfw_core_ShaderProgram_setShaderAttributeValues(
266    JNIEnv* env,
267    jobject thiz,
268    jstring attr_name,
269    jfloatArray values,
270    jint component_count) {
271  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
272  if (program) {
273    // Get the floats to set
274    jfloat* float_ptr = env->GetFloatArrayElements(values, NULL);
275    const int length = env->GetArrayLength(values);
276
277    // Get the program variable to set
278    const std::string attr_string = ToCppString(env, attr_name);
279    ProgramVar program_var = program->GetAttribute(attr_string);
280
281    // Set the variable
282    if (float_ptr && ShaderProgram::IsVarValid(program_var)) {
283      const bool success = program->SetAttributeValues(program_var,
284                                                       reinterpret_cast<float*>(float_ptr),
285                                                       length,
286                                                       component_count);
287      env->ReleaseFloatArrayElements(values, float_ptr, JNI_ABORT);
288      return ToJBool(success);
289    }
290  }
291  return JNI_FALSE;
292}
293
294jboolean Java_android_filterfw_core_ShaderProgram_setShaderAttributeVertexFrame(
295    JNIEnv* env,
296    jobject thiz,
297    jstring attr_name,
298    jobject vertex_frame,
299    jint type,
300    jint component_count,
301    jint stride,
302    jint offset,
303    jboolean normalize) {
304  ShaderProgram* program = ConvertFromJava<ShaderProgram>(env, thiz);
305  if (program) {
306    // Get the vertex frame
307    VertexFrame* v_frame = ConvertFromJava<VertexFrame>(env, vertex_frame);
308
309    // Get the program variable to set
310    const std::string attr_string = ToCppString(env, attr_name);
311    ProgramVar program_var = program->GetAttribute(attr_string);
312
313    // Set the variable
314    if (v_frame && ShaderProgram::IsVarValid(program_var)) {
315      const bool success = program->SetAttributeValues(program_var,
316                                                       v_frame,
317                                                       type,
318                                                       component_count,
319                                                       stride,
320                                                       offset,
321                                                       ToCppBool(normalize));
322      return ToJBool(success);
323    }
324  }
325  return JNI_FALSE;
326}
327