blob: e045f5f36ada21c952c111648bdce700b81e4998 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/**
2 ** Copyright 2007, The Android Open Source Project
3 **
Jack Palevich106006c2009-08-31 17:42:50 -07004 ** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 **
Jack Palevich106006c2009-08-31 17:42:50 -07008 ** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 **
Jack Palevich106006c2009-08-31 17:42:50 -070010 ** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014 ** limitations under the License.
15 */
16
Elliott Hughes8451b252011-04-07 19:17:57 -070017#include "jni.h"
18#include "JNIHelp.h"
John Reckf4faeac2015-03-05 13:50:31 -080019#include "GraphicsJNI.h"
Elliott Hughes8451b252011-04-07 19:17:57 -070020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <math.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <assert.h>
26#include <dlfcn.h>
27
28#include <GLES/gl.h>
Jack Palevicha6276fd2009-12-28 19:31:43 +080029#include <ETC1/etc1.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
Derek Sollenbergereece0dd2014-02-27 14:31:29 -050031#include <SkBitmap.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Andreas Gampeed6b9df2014-11-20 22:02:20 -080033#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35#undef LOG_TAG
36#define LOG_TAG "OpenGLUtil"
37#include <utils/Log.h>
38#include "utils/misc.h"
39
40#include "poly.h"
41
42namespace android {
43
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044static inline
45void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
46 pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
47 pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
48 pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
49 pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
50}
51
52class MallocHelper {
53public:
54 MallocHelper() {
55 mData = 0;
56 }
Jack Palevich106006c2009-08-31 17:42:50 -070057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 ~MallocHelper() {
59 if (mData != 0) {
60 free(mData);
61 }
62 }
Jack Palevich106006c2009-08-31 17:42:50 -070063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 void* alloc(size_t size) {
65 mData = malloc(size);
66 return mData;
67 }
Jack Palevich106006c2009-08-31 17:42:50 -070068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069private:
70 void* mData;
71};
72
73#if 0
74static
75void
76print_poly(const char* label, Poly* pPoly) {
Steve Block6215d3f2012-01-04 20:05:49 +000077 ALOGI("%s: %d verts", label, pPoly->n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 for(int i = 0; i < pPoly->n; i++) {
79 Poly_vert* pV = & pPoly->vert[i];
Steve Block6215d3f2012-01-04 20:05:49 +000080 ALOGI("[%d] %g, %g, %g %g", i, pV->sx, pV->sy, pV->sz, pV->sw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82}
83#endif
84
85static
86int visibilityTest(float* pWS, float* pPositions, int positionsLength,
87 unsigned short* pIndices, int indexCount) {
88 MallocHelper mallocHelper;
89 int result = POLY_CLIP_OUT;
90 float* pTransformed = 0;
91 int transformedIndexCount = 0;
Jack Palevich106006c2009-08-31 17:42:50 -070092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 if ( indexCount < 3 ) {
94 return POLY_CLIP_OUT;
95 }
Jack Palevich106006c2009-08-31 17:42:50 -070096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 // Find out how many vertices we need to transform
98 // We transform every vertex between the min and max indices, inclusive.
99 // This is OK for the data sets we expect to use with this function, but
100 // for other loads it might be better to use a more sophisticated vertex
101 // cache of some sort.
Jack Palevich106006c2009-08-31 17:42:50 -0700102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 int minIndex = 65536;
104 int maxIndex = -1;
105 for(int i = 0; i < indexCount; i++) {
106 int index = pIndices[i];
107 if ( index < minIndex ) {
108 minIndex = index;
109 }
110 if ( index > maxIndex ) {
111 maxIndex = index;
112 }
113 }
Jack Palevich106006c2009-08-31 17:42:50 -0700114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 if ( maxIndex * 3 > positionsLength) {
116 return -1;
117 }
Jack Palevich106006c2009-08-31 17:42:50 -0700118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 transformedIndexCount = maxIndex - minIndex + 1;
120 pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
Jack Palevich106006c2009-08-31 17:42:50 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 if (pTransformed == 0 ) {
123 return -2;
124 }
Jack Palevich106006c2009-08-31 17:42:50 -0700125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 // Transform the vertices
127 {
128 const float* pSrc = pPositions + 3 * minIndex;
129 float* pDst = pTransformed;
130 for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
131 mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
132 }
133 }
Jack Palevich106006c2009-08-31 17:42:50 -0700134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 // Clip the triangles
Jack Palevich106006c2009-08-31 17:42:50 -0700136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 Poly poly;
138 float* pDest = & poly.vert[0].sx;
139 for (int i = 0; i < indexCount; i += 3) {
140 poly.n = 3;
141 memcpy(pDest , pTransformed + 4 * (pIndices[i ] - minIndex), 4 * sizeof(float));
142 memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
143 memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
144 result = poly_clip_to_frustum(&poly);
145 if ( result != POLY_CLIP_OUT) {
146 return result;
147 }
148 }
149
150 return result;
151}
152
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700153class ByteArrayGetter {
154public:
155 static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
156 return _env->GetByteArrayElements(array, is_copy);
157 }
158};
159class BooleanArrayGetter {
160public:
161 static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
162 return _env->GetBooleanArrayElements(array, is_copy);
163 }
164};
165class CharArrayGetter {
166public:
167 static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
168 return _env->GetCharArrayElements(array, is_copy);
169 }
170};
171class ShortArrayGetter {
172public:
173 static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
174 return _env->GetShortArrayElements(array, is_copy);
175 }
176};
177class IntArrayGetter {
178public:
179 static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
180 return _env->GetIntArrayElements(array, is_copy);
181 }
182};
183class LongArrayGetter {
184public:
185 static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
186 return _env->GetLongArrayElements(array, is_copy);
187 }
188};
189class FloatArrayGetter {
190public:
191 static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
192 return _env->GetFloatArrayElements(array, is_copy);
193 }
194};
195class DoubleArrayGetter {
196public:
197 static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
198 return _env->GetDoubleArrayElements(array, is_copy);
199 }
200};
201
202class ByteArrayReleaser {
203public:
204 static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jint mode) {
205 _env->ReleaseByteArrayElements(array, data, mode);
206 }
207};
208class BooleanArrayReleaser {
209public:
210 static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jint mode) {
211 _env->ReleaseBooleanArrayElements(array, data, mode);
212 }
213};
214class CharArrayReleaser {
215public:
216 static void Release(JNIEnv* _env, jcharArray array, jchar* data, jint mode) {
217 _env->ReleaseCharArrayElements(array, data, mode);
218 }
219};
220class ShortArrayReleaser {
221public:
222 static void Release(JNIEnv* _env, jshortArray array, jshort* data, jint mode) {
223 _env->ReleaseShortArrayElements(array, data, mode);
224 }
225};
226class IntArrayReleaser {
227public:
228 static void Release(JNIEnv* _env, jintArray array, jint* data, jint mode) {
229 _env->ReleaseIntArrayElements(array, data, mode);
230 }
231};
232class LongArrayReleaser {
233public:
234 static void Release(JNIEnv* _env, jlongArray array, jlong* data, jint mode) {
235 _env->ReleaseLongArrayElements(array, data, mode);
236 }
237};
238class FloatArrayReleaser {
239public:
240 static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jint mode) {
241 _env->ReleaseFloatArrayElements(array, data, mode);
242 }
243};
244class DoubleArrayReleaser {
245public:
246 static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jint mode) {
247 _env->ReleaseDoubleArrayElements(array, data, mode);
248 }
249};
250
251template<class JArray, class T, class ArrayGetter, class ArrayReleaser>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252class ArrayHelper {
253public:
254 ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
255 mEnv = env;
256 mRef = ref;
257 mOffset = offset;
258 mMinSize = minSize;
259 mBase = 0;
260 mReleaseParam = JNI_ABORT;
261 }
262
263 ~ArrayHelper() {
264 if (mBase) {
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700265 ArrayReleaser::Release(mEnv, mRef, mBase, mReleaseParam);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 }
267 }
Jack Palevich106006c2009-08-31 17:42:50 -0700268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 // We seperate the bounds check from the initialization because we want to
270 // be able to bounds-check multiple arrays, and we can't throw an exception
271 // after we've called GetPrimitiveArrayCritical.
Jack Palevich106006c2009-08-31 17:42:50 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 // Return true if the bounds check succeeded
274 // Else instruct the runtime to throw an exception
Jack Palevich106006c2009-08-31 17:42:50 -0700275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 bool check() {
277 if ( ! mRef) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700278 doThrowIAE(mEnv, "array == null");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 return false;
280 }
281 if ( mOffset < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700282 doThrowIAE(mEnv, "offset < 0");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 return false;
284 }
285 mLength = mEnv->GetArrayLength(mRef) - mOffset;
286 if (mLength < mMinSize ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700287 doThrowIAE(mEnv, "length - offset < n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 return false;
289 }
290 return true;
291 }
Jack Palevich106006c2009-08-31 17:42:50 -0700292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 // Bind the array.
Jack Palevich106006c2009-08-31 17:42:50 -0700294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 void bind() {
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700296 mBase = (T*) ArrayGetter::Get(mEnv, mRef, (jboolean *) 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 mData = mBase + mOffset;
298 }
299
300 void commitChanges() {
301 mReleaseParam = 0;
302 }
Jack Palevich106006c2009-08-31 17:42:50 -0700303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 T* mData;
305 int mLength;
Jack Palevich106006c2009-08-31 17:42:50 -0700306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307private:
308 T* mBase;
309 JNIEnv* mEnv;
310 JArray mRef;
311 jint mOffset;
312 jint mMinSize;
313 int mReleaseParam;
314};
315
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700316typedef ArrayHelper<jfloatArray, float, FloatArrayGetter, FloatArrayReleaser> FloatArrayHelper;
317typedef ArrayHelper<jcharArray, unsigned short, CharArrayGetter, CharArrayReleaser> UnsignedShortArrayHelper;
318typedef ArrayHelper<jintArray, int, IntArrayGetter, IntArrayReleaser> IntArrayHelper;
319typedef ArrayHelper<jbyteArray, unsigned char, ByteArrayGetter, ByteArrayReleaser> ByteArrayHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320
321inline float distance2(float x, float y, float z) {
322 return x * x + y * y + z * z;
323}
324
325inline float distance(float x, float y, float z) {
326 return sqrtf(distance2(x, y, z));
327}
Jack Palevich106006c2009-08-31 17:42:50 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329static
330void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
331 jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
332 jfloatArray sphere_ref, jint sphereOffset) {
333 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
334 FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 bool checkOK = positions.check() && sphere.check();
337 if (! checkOK) {
338 return;
339 }
Jack Palevich106006c2009-08-31 17:42:50 -0700340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 positions.bind();
342 sphere.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 if ( positionsCount < 1 ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700345 doThrowIAE(env, "positionsCount < 1");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return;
347 }
Jack Palevich106006c2009-08-31 17:42:50 -0700348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 const float* pSrc = positions.mData;
Jack Palevich106006c2009-08-31 17:42:50 -0700350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 // find bounding box
352 float x0 = *pSrc++;
353 float x1 = x0;
354 float y0 = *pSrc++;
355 float y1 = y0;
356 float z0 = *pSrc++;
357 float z1 = z0;
Jack Palevich106006c2009-08-31 17:42:50 -0700358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 for(int i = 1; i < positionsCount; i++) {
360 {
361 float x = *pSrc++;
362 if (x < x0) {
363 x0 = x;
364 }
365 else if (x > x1) {
366 x1 = x;
367 }
368 }
369 {
370 float y = *pSrc++;
371 if (y < y0) {
372 y0 = y;
373 }
374 else if (y > y1) {
375 y1 = y;
376 }
377 }
378 {
379 float z = *pSrc++;
380 if (z < z0) {
381 z0 = z;
382 }
383 else if (z > z1) {
384 z1 = z;
385 }
386 }
387 }
Jack Palevich106006c2009-08-31 17:42:50 -0700388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 // Because we know our input meshes fit pretty well into bounding boxes,
390 // just take the diagonal of the box as defining our sphere.
391 float* pSphere = sphere.mData;
392 float dx = x1 - x0;
393 float dy = y1 - y0;
394 float dz = z1 - z0;
395 *pSphere++ = x0 + dx * 0.5f;
396 *pSphere++ = y0 + dy * 0.5f;
397 *pSphere++ = z0 + dz * 0.5f;
398 *pSphere++ = distance(dx, dy, dz) * 0.5f;
Jack Palevich106006c2009-08-31 17:42:50 -0700399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 sphere.commitChanges();
401}
402
403static void normalizePlane(float* p) {
404 float rdist = 1.0f / distance(p[0], p[1], p[2]);
405 for(int i = 0; i < 4; i++) {
406 p[i] *= rdist;
407 }
408}
409
410static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
411 return x0 * x1 + y0 * y1 + z0 * z1;
412}
413
414static inline float signedDistance(const float* pPlane, float x, float y, float z) {
415 return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
416}
417
418// Return true if the sphere intersects or is inside the frustum
419
420static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
421 float x = pSphere[0];
422 float y = pSphere[1];
423 float z = pSphere[2];
424 float negRadius = -pSphere[3];
425 for (int i = 0; i < 6; i++, pFrustum += 4) {
426 if (signedDistance(pFrustum, x, y, z) <= negRadius) {
427 return false;
428 }
429 }
430 return true;
431}
432
433static void computeFrustum(const float* m, float* f) {
434 float m3 = m[3];
435 float m7 = m[7];
436 float m11 = m[11];
437 float m15 = m[15];
438 // right
439 f[0] = m3 - m[0];
440 f[1] = m7 - m[4];
441 f[2] = m11 - m[8];
442 f[3] = m15 - m[12];
443 normalizePlane(f);
444 f+= 4;
445
Jack Palevich106006c2009-08-31 17:42:50 -0700446 // left
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 f[0] = m3 + m[0];
448 f[1] = m7 + m[4];
449 f[2] = m11 + m[8];
450 f[3] = m15 + m[12];
451 normalizePlane(f);
452 f+= 4;
453
454 // top
455 f[0] = m3 - m[1];
456 f[1] = m7 - m[5];
457 f[2] = m11 - m[9];
458 f[3] = m15 - m[13];
459 normalizePlane(f);
460 f+= 4;
461
462 // bottom
463 f[0] = m3 + m[1];
464 f[1] = m7 + m[5];
465 f[2] = m11 + m[9];
466 f[3] = m15 + m[13];
467 normalizePlane(f);
468 f+= 4;
469
470 // far
471 f[0] = m3 - m[2];
472 f[1] = m7 - m[6];
473 f[2] = m11 - m[10];
474 f[3] = m15 - m[14];
475 normalizePlane(f);
476 f+= 4;
477
478 // near
479 f[0] = m3 + m[2];
480 f[1] = m7 + m[6];
481 f[2] = m11 + m[10];
482 f[3] = m15 + m[14];
483 normalizePlane(f);
484}
485
486static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000487jint util_frustumCullSpheres(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 jfloatArray mvp_ref, jint mvpOffset,
489 jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
490 jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
491 float frustum[6*4];
492 int outputCount;
493 int* pResults;
494 float* pSphere;
495 FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
496 FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
497 IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
Jack Palevich106006c2009-08-31 17:42:50 -0700498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 bool initializedOK = mvp.check() && spheres.check() && results.check();
500 if (! initializedOK) {
501 return -1;
502 }
Jack Palevich106006c2009-08-31 17:42:50 -0700503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 mvp.bind();
505 spheres.bind();
506 results.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 computeFrustum(mvp.mData, frustum);
Jack Palevich106006c2009-08-31 17:42:50 -0700509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 // Cull the spheres
Jack Palevich106006c2009-08-31 17:42:50 -0700511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 pSphere = spheres.mData;
513 pResults = results.mData;
514 outputCount = 0;
515 for(int i = 0; i < spheresCount; i++, pSphere += 4) {
516 if (sphereHitsFrustum(frustum, pSphere)) {
517 if (outputCount < resultsCapacity) {
518 *pResults++ = i;
519 }
520 outputCount++;
521 }
522 }
523 results.commitChanges();
524 return outputCount;
525}
526
527/*
528 public native int visibilityTest(float[] ws, int wsOffset,
529 float[] positions, int positionsOffset,
530 char[] indices, int indicesOffset, int indexCount);
531 */
532
533static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000534jint util_visibilityTest(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 jfloatArray ws_ref, jint wsOffset,
536 jfloatArray positions_ref, jint positionsOffset,
537 jcharArray indices_ref, jint indicesOffset, jint indexCount) {
Jack Palevich106006c2009-08-31 17:42:50 -0700538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
540 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
541 UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
Jack Palevich106006c2009-08-31 17:42:50 -0700542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 bool checkOK = ws.check() && positions.check() && indices.check();
544 if (! checkOK) {
545 // Return value will be ignored, because an exception has been thrown.
546 return -1;
547 }
Jack Palevich106006c2009-08-31 17:42:50 -0700548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 if (indices.mLength < indexCount) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700550 doThrowIAE(env, "length < offset + indexCount");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 return -1;
552 }
Jack Palevich106006c2009-08-31 17:42:50 -0700553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 ws.bind();
555 positions.bind();
556 indices.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 return visibilityTest(ws.mData,
559 positions.mData, positions.mLength,
560 indices.mData, indexCount);
561}
562
563#define I(_i, _j) ((_j)+ 4*(_i))
564
565static
566void multiplyMM(float* r, const float* lhs, const float* rhs)
567{
568 for (int i=0 ; i<4 ; i++) {
Dan Albert46d84442014-11-18 16:07:51 -0800569 const float rhs_i0 = rhs[ I(i,0) ];
570 float ri0 = lhs[ I(0,0) ] * rhs_i0;
571 float ri1 = lhs[ I(0,1) ] * rhs_i0;
572 float ri2 = lhs[ I(0,2) ] * rhs_i0;
573 float ri3 = lhs[ I(0,3) ] * rhs_i0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 for (int j=1 ; j<4 ; j++) {
Dan Albert46d84442014-11-18 16:07:51 -0800575 const float rhs_ij = rhs[ I(i,j) ];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 ri0 += lhs[ I(j,0) ] * rhs_ij;
577 ri1 += lhs[ I(j,1) ] * rhs_ij;
578 ri2 += lhs[ I(j,2) ] * rhs_ij;
579 ri3 += lhs[ I(j,3) ] * rhs_ij;
580 }
581 r[ I(i,0) ] = ri0;
582 r[ I(i,1) ] = ri1;
583 r[ I(i,2) ] = ri2;
584 r[ I(i,3) ] = ri3;
585 }
586}
587
588static
589void util_multiplyMM(JNIEnv *env, jclass clazz,
590 jfloatArray result_ref, jint resultOffset,
591 jfloatArray lhs_ref, jint lhsOffset,
592 jfloatArray rhs_ref, jint rhsOffset) {
593
594 FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
595 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
596 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
Jack Palevich106006c2009-08-31 17:42:50 -0700597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 bool checkOK = resultMat.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 if ( !checkOK ) {
601 return;
602 }
Jack Palevich106006c2009-08-31 17:42:50 -0700603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 resultMat.bind();
605 lhs.bind();
606 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 resultMat.commitChanges();
611}
612
613static
614void multiplyMV(float* r, const float* lhs, const float* rhs)
615{
616 mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
617}
618
619static
620void util_multiplyMV(JNIEnv *env, jclass clazz,
621 jfloatArray result_ref, jint resultOffset,
622 jfloatArray lhs_ref, jint lhsOffset,
623 jfloatArray rhs_ref, jint rhsOffset) {
624
625 FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
626 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
627 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 bool checkOK = resultV.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 if ( !checkOK ) {
632 return;
633 }
Jack Palevich106006c2009-08-31 17:42:50 -0700634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 resultV.bind();
636 lhs.bind();
637 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 multiplyMV(resultV.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 resultV.commitChanges();
642}
643
644// ---------------------------------------------------------------------------
645
Siva Velusamy64d10a12012-03-09 14:21:28 -0800646extern void setGLDebugLevel(int level);
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800647void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
Siva Velusamy64d10a12012-03-09 14:21:28 -0800648{
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800649 setGLDebugLevel(level);
Siva Velusamy64d10a12012-03-09 14:21:28 -0800650}
651
Mike Reed1103b322014-07-08 12:36:44 -0400652static int checkFormat(SkColorType colorType, int format, int type)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653{
Mike Reed1103b322014-07-08 12:36:44 -0400654 switch(colorType) {
655 case kIndex_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 if (format == GL_PALETTE8_RGBA8_OES)
657 return 0;
Mike Reed1103b322014-07-08 12:36:44 -0400658 case kN32_SkColorType:
659 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 if (type == GL_UNSIGNED_BYTE)
661 return 0;
Mike Reed1103b322014-07-08 12:36:44 -0400662 case kARGB_4444_SkColorType:
663 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 switch (type) {
665 case GL_UNSIGNED_SHORT_4_4_4_4:
666 case GL_UNSIGNED_SHORT_5_6_5:
667 case GL_UNSIGNED_SHORT_5_5_5_1:
668 return 0;
669 case GL_UNSIGNED_BYTE:
670 if (format == GL_LUMINANCE_ALPHA)
671 return 0;
672 }
673 break;
674 default:
675 break;
676 }
677 return -1;
678}
679
Mike Reed1103b322014-07-08 12:36:44 -0400680static int getInternalFormat(SkColorType colorType)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681{
Mike Reed1103b322014-07-08 12:36:44 -0400682 switch(colorType) {
683 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 return GL_ALPHA;
Mike Reed1103b322014-07-08 12:36:44 -0400685 case kARGB_4444_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400687 case kN32_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400689 case kIndex_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 return GL_PALETTE8_RGBA8_OES;
Mike Reed1103b322014-07-08 12:36:44 -0400691 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 return GL_RGB;
693 default:
694 return -1;
695 }
696}
697
Mike Reed1103b322014-07-08 12:36:44 -0400698static int getType(SkColorType colorType)
Jack Palevich708c17b2009-03-24 21:05:22 -0700699{
Mike Reed1103b322014-07-08 12:36:44 -0400700 switch(colorType) {
701 case kAlpha_8_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700702 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400703 case kARGB_4444_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700704 return GL_UNSIGNED_SHORT_4_4_4_4;
Mike Reed1103b322014-07-08 12:36:44 -0400705 case kN32_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700706 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400707 case kIndex_8_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700708 return -1; // No type for compressed data.
Mike Reed1103b322014-07-08 12:36:44 -0400709 case kRGB_565_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700710 return GL_UNSIGNED_SHORT_5_6_5;
711 default:
712 return -1;
713 }
714}
715
716static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
717 jobject jbitmap)
718{
John Recked207b92015-04-10 13:52:57 -0700719 SkBitmap nativeBitmap;
720 GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
721 return getInternalFormat(nativeBitmap.colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700722}
723
724static jint util_getType(JNIEnv *env, jclass clazz,
725 jobject jbitmap)
726{
John Recked207b92015-04-10 13:52:57 -0700727 SkBitmap nativeBitmap;
728 GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
729 return getType(nativeBitmap.colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700730}
731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732static jint util_texImage2D(JNIEnv *env, jclass clazz,
733 jint target, jint level, jint internalformat,
734 jobject jbitmap, jint type, jint border)
735{
John Recked207b92015-04-10 13:52:57 -0700736 SkBitmap bitmap;
737 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400738 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 if (internalformat < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400740 internalformat = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
Jack Palevich708c17b2009-03-24 21:05:22 -0700742 if (type < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400743 type = getType(colorType);
Jack Palevich708c17b2009-03-24 21:05:22 -0700744 }
Mike Reed1103b322014-07-08 12:36:44 -0400745 int err = checkFormat(colorType, internalformat, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700747 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 bitmap.lockPixels();
749 const int w = bitmap.width();
750 const int h = bitmap.height();
751 const void* p = bitmap.getPixels();
752 if (internalformat == GL_PALETTE8_RGBA8_OES) {
753 if (sizeof(SkPMColor) != sizeof(uint32_t)) {
754 err = -1;
755 goto error;
756 }
757 const size_t size = bitmap.getSize();
758 const size_t palette_size = 256*sizeof(SkPMColor);
Jack Palevich106006c2009-08-31 17:42:50 -0700759 const size_t imageSize = size + palette_size;
760 void* const data = malloc(imageSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 if (data) {
762 void* const pixels = (char*)data + palette_size;
763 SkColorTable* ctable = bitmap.getColorTable();
Mike Reed71487eb2014-11-19 16:13:20 -0500764 memcpy(data, ctable->readColors(), ctable->count() * sizeof(SkPMColor));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 memcpy(pixels, p, size);
Jack Palevich106006c2009-08-31 17:42:50 -0700766 glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 free(data);
768 } else {
769 err = -1;
770 }
771 } else {
772 glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
773 }
774error:
775 bitmap.unlockPixels();
776 return err;
777}
778
779static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
780 jint target, jint level, jint xoffset, jint yoffset,
781 jobject jbitmap, jint format, jint type)
782{
John Recked207b92015-04-10 13:52:57 -0700783 SkBitmap bitmap;
784 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400785 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 if (format < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400787 format = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 if (format == GL_PALETTE8_RGBA8_OES)
789 return -1; // glCompressedTexSubImage2D() not supported
790 }
Mike Reed1103b322014-07-08 12:36:44 -0400791 int err = checkFormat(colorType, format, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700793 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 bitmap.lockPixels();
795 const int w = bitmap.width();
796 const int h = bitmap.height();
797 const void* p = bitmap.getPixels();
798 glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
799 bitmap.unlockPixels();
800 return 0;
801}
802
803/*
Jack Palevicha6276fd2009-12-28 19:31:43 +0800804 * ETC1 methods.
805 */
806
807static jclass nioAccessClass;
808static jclass bufferClass;
809static jmethodID getBasePointerID;
810static jmethodID getBaseArrayID;
811static jmethodID getBaseArrayOffsetID;
812static jfieldID positionID;
813static jfieldID limitID;
814static jfieldID elementSizeShiftID;
815
816/* Cache method IDs each time the class is loaded. */
817
818static void
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800819nativeClassInitBuffer(JNIEnv *env)
Jack Palevicha6276fd2009-12-28 19:31:43 +0800820{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800821 jclass nioAccessClassLocal = FindClassOrDie(env, "java/nio/NIOAccess");
822 nioAccessClass = MakeGlobalRefOrDie(env, nioAccessClassLocal);
823 getBasePointerID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800824 "getBasePointer", "(Ljava/nio/Buffer;)J");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800825 getBaseArrayID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800826 "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800827 getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800828 "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800829
830 jclass bufferClassLocal = FindClassOrDie(env, "java/nio/Buffer");
831 bufferClass = MakeGlobalRefOrDie(env, bufferClassLocal);
832 positionID = GetFieldIDOrDie(env, bufferClass, "position", "I");
833 limitID = GetFieldIDOrDie(env, bufferClass, "limit", "I");
834 elementSizeShiftID = GetFieldIDOrDie(env, bufferClass, "_elementSizeShift", "I");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800835}
836
837static void *
838getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
839{
840 jint position;
841 jint limit;
842 jint elementSizeShift;
843 jlong pointer;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800844
845 position = _env->GetIntField(buffer, positionID);
846 limit = _env->GetIntField(buffer, limitID);
847 elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
848 *remaining = (limit - position) << elementSizeShift;
849 pointer = _env->CallStaticLongMethod(nioAccessClass,
850 getBasePointerID, buffer);
851 if (pointer != 0L) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000852 return reinterpret_cast<void *>(pointer);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800853 }
854 return NULL;
855}
856
857class BufferHelper {
858public:
859 BufferHelper(JNIEnv *env, jobject buffer) {
860 mEnv = env;
861 mBuffer = buffer;
862 mData = NULL;
863 mRemaining = 0;
864 }
865
866 bool checkPointer(const char* errorMessage) {
867 if (mBuffer) {
868 mData = getPointer(mEnv, mBuffer, &mRemaining);
869 if (mData == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700870 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800871 }
872 return mData != NULL;
873 } else {
Elliott Hughes8451b252011-04-07 19:17:57 -0700874 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800875 return false;
876 }
877 }
878
879 inline void* getData() {
880 return mData;
881 }
882
883 inline jint remaining() {
884 return mRemaining;
885 }
886
887private:
888 JNIEnv* mEnv;
889 jobject mBuffer;
890 void* mData;
891 jint mRemaining;
892};
893
894/**
895 * Encode a block of pixels.
896 *
897 * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
898 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
899 * value of pixel (x, y).
900 *
901 * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
902 * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
903 *
904 * @param out an ETC1 compressed version of the data.
905 *
906 */
907static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
908 jobject in, jint validPixelMask, jobject out) {
909 if (validPixelMask < 0 || validPixelMask > 15) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700910 doThrowIAE(env, "validPixelMask");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800911 return;
912 }
913 BufferHelper inB(env, in);
914 BufferHelper outB(env, out);
915 if (inB.checkPointer("in") && outB.checkPointer("out")) {
916 if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700917 doThrowIAE(env, "in's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800918 } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700919 doThrowIAE(env, "out's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800920 } else {
921 etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
922 (etc1_byte*) outB.getData());
923 }
924 }
925}
926
927/**
928 * Decode a block of pixels.
929 *
930 * @param in an ETC1 compressed version of the data.
931 *
932 * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
933 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
934 * value of pixel (x, y).
935 */
936static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
937 jobject in, jobject out){
938 BufferHelper inB(env, in);
939 BufferHelper outB(env, out);
940 if (inB.checkPointer("in") && outB.checkPointer("out")) {
941 if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700942 doThrowIAE(env, "in's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800943 } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700944 doThrowIAE(env, "out's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800945 } else {
946 etc1_decode_block((etc1_byte*) inB.getData(),
947 (etc1_byte*) outB.getData());
948 }
949 }
950}
951
952/**
953 * Return the size of the encoded image data (does not include size of PKM header).
954 */
955static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
956 jint width, jint height) {
957 return etc1_get_encoded_data_size(width, height);
958}
959
960/**
961 * Encode an entire image.
962 * @param in pointer to the image data. Formatted such that
963 * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
964 * @param out pointer to encoded data. Must be large enough to store entire encoded image.
965 */
966static void etc1_encodeImage(JNIEnv *env, jclass clazz,
967 jobject in, jint width, jint height,
968 jint pixelSize, jint stride, jobject out) {
969 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700970 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800971 return;
972 }
973 BufferHelper inB(env, in);
974 BufferHelper outB(env, out);
975 if (inB.checkPointer("in") && outB.checkPointer("out")) {
976 jint imageSize = stride * height;
977 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
978 if (inB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700979 doThrowIAE(env, "in's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800980 } else if (outB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700981 doThrowIAE(env, "out's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800982 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800983 etc1_encode_image((etc1_byte*) inB.getData(), width, height, pixelSize, stride,
984 (etc1_byte*) outB.getData());
Jack Palevicha6276fd2009-12-28 19:31:43 +0800985 }
986 }
987}
988
989/**
990 * Decode an entire image.
991 * @param in the encoded data.
992 * @param out pointer to the image data. Will be written such that
993 * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
994 * large enough to store entire image.
995 */
996static void etc1_decodeImage(JNIEnv *env, jclass clazz,
997 jobject in, jobject out,
998 jint width, jint height,
999 jint pixelSize, jint stride) {
1000 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001001 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001002 return;
1003 }
1004 BufferHelper inB(env, in);
1005 BufferHelper outB(env, out);
1006 if (inB.checkPointer("in") && outB.checkPointer("out")) {
1007 jint imageSize = stride * height;
1008 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
1009 if (inB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001010 doThrowIAE(env, "in's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001011 } else if (outB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001012 doThrowIAE(env, "out's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001013 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001014 etc1_decode_image((etc1_byte*) inB.getData(), (etc1_byte*) outB.getData(),
1015 width, height, pixelSize, stride);
Jack Palevicha6276fd2009-12-28 19:31:43 +08001016 }
1017 }
1018}
1019
1020/**
1021 * Format a PKM header
1022 */
1023static void etc1_formatHeader(JNIEnv *env, jclass clazz,
1024 jobject header, jint width, jint height) {
1025 BufferHelper headerB(env, header);
1026 if (headerB.checkPointer("header") ){
1027 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001028 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001029 } else {
1030 etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
1031 }
1032 }
1033}
1034
1035/**
1036 * Check if a PKM header is correctly formatted.
1037 */
1038static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
1039 jobject header) {
1040 jboolean result = false;
1041 BufferHelper headerB(env, header);
1042 if (headerB.checkPointer("header") ){
1043 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001044 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001045 } else {
1046 result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
1047 }
1048 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +00001049 return result ? JNI_TRUE : JNI_FALSE;
Jack Palevicha6276fd2009-12-28 19:31:43 +08001050}
1051
1052/**
1053 * Read the image width from a PKM header
1054 */
1055static jint etc1_getWidth(JNIEnv *env, jclass clazz,
1056 jobject header) {
1057 jint result = 0;
1058 BufferHelper headerB(env, header);
1059 if (headerB.checkPointer("header") ){
1060 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001061 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001062 } else {
1063 result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
1064 }
1065 }
1066 return result;
1067}
1068
1069/**
1070 * Read the image height from a PKM header
1071 */
Ashok Bhat36bef0b2014-01-20 20:08:01 +00001072static jint etc1_getHeight(JNIEnv *env, jclass clazz,
Jack Palevicha6276fd2009-12-28 19:31:43 +08001073 jobject header) {
1074 jint result = 0;
1075 BufferHelper headerB(env, header);
1076 if (headerB.checkPointer("header") ){
1077 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001078 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001079 } else {
1080 result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
1081 }
1082 }
1083 return result;
1084}
1085
1086/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 * JNI registration
1088 */
1089
Daniel Micay76f6a862015-09-19 17:31:01 -04001090static const JNINativeMethod gMatrixMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001091 { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
1092 { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093};
1094
Daniel Micay76f6a862015-09-19 17:31:01 -04001095static const JNINativeMethod gVisibilityMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001096 { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
Jack Palevich106006c2009-08-31 17:42:50 -07001098 { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099};
1100
Daniel Micay76f6a862015-09-19 17:31:01 -04001101static const JNINativeMethod gUtilsMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001102 { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
1103 { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
1104 { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
1105 { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
Siva Velusamy0c1761b2012-12-14 17:09:06 -08001106 { "setTracingLevel", "(I)V", (void*)setTracingLevel },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107};
1108
Daniel Micay76f6a862015-09-19 17:31:01 -04001109static const JNINativeMethod gEtc1Methods[] = {
Jack Palevicha6276fd2009-12-28 19:31:43 +08001110 { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
1111 { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
1112 { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
1113 { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
1114 { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
1115 { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
1116 { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
1117 { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
1118 { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
1119};
1120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121typedef struct _ClassRegistrationInfo {
1122 const char* classPath;
Daniel Micay76f6a862015-09-19 17:31:01 -04001123 const JNINativeMethod* methods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 size_t methodCount;
1125} ClassRegistrationInfo;
1126
Daniel Micay76f6a862015-09-19 17:31:01 -04001127static const ClassRegistrationInfo gClasses[] = {
Elliott Hughes8451b252011-04-07 19:17:57 -07001128 {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
1129 {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
1130 {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
1131 {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132};
1133
1134int register_android_opengl_classes(JNIEnv* env)
1135{
Jack Palevicha6276fd2009-12-28 19:31:43 +08001136 nativeClassInitBuffer(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 int result = 0;
1138 for (int i = 0; i < NELEM(gClasses); i++) {
Daniel Micay76f6a862015-09-19 17:31:01 -04001139 const ClassRegistrationInfo* cri = &gClasses[i];
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001140 result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 }
1142 return result;
1143}
1144
1145} // namespace android