blob: 1522c20dbe2f5f4c63277647ed7b9d82de7ff1c8 [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"
Steven Moreland2279b252017-07-19 09:50:45 -070018#include <nativehelper/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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052#if 0
53static
54void
55print_poly(const char* label, Poly* pPoly) {
Steve Block6215d3f2012-01-04 20:05:49 +000056 ALOGI("%s: %d verts", label, pPoly->n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 for(int i = 0; i < pPoly->n; i++) {
58 Poly_vert* pV = & pPoly->vert[i];
Steve Block6215d3f2012-01-04 20:05:49 +000059 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 -080060 }
61}
62#endif
63
64static
65int visibilityTest(float* pWS, float* pPositions, int positionsLength,
66 unsigned short* pIndices, int indexCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 int result = POLY_CLIP_OUT;
Jack Palevich106006c2009-08-31 17:42:50 -070068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 if ( indexCount < 3 ) {
70 return POLY_CLIP_OUT;
71 }
Jack Palevich106006c2009-08-31 17:42:50 -070072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 // Find out how many vertices we need to transform
74 // We transform every vertex between the min and max indices, inclusive.
75 // This is OK for the data sets we expect to use with this function, but
76 // for other loads it might be better to use a more sophisticated vertex
77 // cache of some sort.
Jack Palevich106006c2009-08-31 17:42:50 -070078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 int minIndex = 65536;
80 int maxIndex = -1;
81 for(int i = 0; i < indexCount; i++) {
82 int index = pIndices[i];
83 if ( index < minIndex ) {
84 minIndex = index;
85 }
86 if ( index > maxIndex ) {
87 maxIndex = index;
88 }
89 }
Jack Palevich106006c2009-08-31 17:42:50 -070090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 if ( maxIndex * 3 > positionsLength) {
92 return -1;
93 }
Jack Palevich106006c2009-08-31 17:42:50 -070094
Elliott Hughes46143e12017-06-21 11:52:35 -070095 int transformedIndexCount = maxIndex - minIndex + 1;
96 std::unique_ptr<float[]> holder{new float[transformedIndexCount * 4]};
97 float* pTransformed = holder.get();
Jack Palevich106006c2009-08-31 17:42:50 -070098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 if (pTransformed == 0 ) {
100 return -2;
101 }
Jack Palevich106006c2009-08-31 17:42:50 -0700102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 // Transform the vertices
104 {
105 const float* pSrc = pPositions + 3 * minIndex;
106 float* pDst = pTransformed;
107 for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
108 mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
109 }
110 }
Jack Palevich106006c2009-08-31 17:42:50 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 // Clip the triangles
Jack Palevich106006c2009-08-31 17:42:50 -0700113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 Poly poly;
115 float* pDest = & poly.vert[0].sx;
116 for (int i = 0; i < indexCount; i += 3) {
117 poly.n = 3;
118 memcpy(pDest , pTransformed + 4 * (pIndices[i ] - minIndex), 4 * sizeof(float));
119 memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
120 memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
121 result = poly_clip_to_frustum(&poly);
122 if ( result != POLY_CLIP_OUT) {
123 return result;
124 }
125 }
126
127 return result;
128}
129
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700130class ByteArrayGetter {
131public:
132 static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
133 return _env->GetByteArrayElements(array, is_copy);
134 }
135};
136class BooleanArrayGetter {
137public:
138 static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
139 return _env->GetBooleanArrayElements(array, is_copy);
140 }
141};
142class CharArrayGetter {
143public:
144 static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
145 return _env->GetCharArrayElements(array, is_copy);
146 }
147};
148class ShortArrayGetter {
149public:
150 static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
151 return _env->GetShortArrayElements(array, is_copy);
152 }
153};
154class IntArrayGetter {
155public:
156 static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
157 return _env->GetIntArrayElements(array, is_copy);
158 }
159};
160class LongArrayGetter {
161public:
162 static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
163 return _env->GetLongArrayElements(array, is_copy);
164 }
165};
166class FloatArrayGetter {
167public:
168 static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
169 return _env->GetFloatArrayElements(array, is_copy);
170 }
171};
172class DoubleArrayGetter {
173public:
174 static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
175 return _env->GetDoubleArrayElements(array, is_copy);
176 }
177};
178
179class ByteArrayReleaser {
180public:
181 static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jint mode) {
182 _env->ReleaseByteArrayElements(array, data, mode);
183 }
184};
185class BooleanArrayReleaser {
186public:
187 static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jint mode) {
188 _env->ReleaseBooleanArrayElements(array, data, mode);
189 }
190};
191class CharArrayReleaser {
192public:
193 static void Release(JNIEnv* _env, jcharArray array, jchar* data, jint mode) {
194 _env->ReleaseCharArrayElements(array, data, mode);
195 }
196};
197class ShortArrayReleaser {
198public:
199 static void Release(JNIEnv* _env, jshortArray array, jshort* data, jint mode) {
200 _env->ReleaseShortArrayElements(array, data, mode);
201 }
202};
203class IntArrayReleaser {
204public:
205 static void Release(JNIEnv* _env, jintArray array, jint* data, jint mode) {
206 _env->ReleaseIntArrayElements(array, data, mode);
207 }
208};
209class LongArrayReleaser {
210public:
211 static void Release(JNIEnv* _env, jlongArray array, jlong* data, jint mode) {
212 _env->ReleaseLongArrayElements(array, data, mode);
213 }
214};
215class FloatArrayReleaser {
216public:
217 static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jint mode) {
218 _env->ReleaseFloatArrayElements(array, data, mode);
219 }
220};
221class DoubleArrayReleaser {
222public:
223 static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jint mode) {
224 _env->ReleaseDoubleArrayElements(array, data, mode);
225 }
226};
227
228template<class JArray, class T, class ArrayGetter, class ArrayReleaser>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229class ArrayHelper {
230public:
231 ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
232 mEnv = env;
233 mRef = ref;
234 mOffset = offset;
235 mMinSize = minSize;
236 mBase = 0;
237 mReleaseParam = JNI_ABORT;
238 }
239
240 ~ArrayHelper() {
241 if (mBase) {
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700242 ArrayReleaser::Release(mEnv, mRef, mBase, mReleaseParam);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
244 }
Jack Palevich106006c2009-08-31 17:42:50 -0700245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 // We seperate the bounds check from the initialization because we want to
247 // be able to bounds-check multiple arrays, and we can't throw an exception
248 // after we've called GetPrimitiveArrayCritical.
Jack Palevich106006c2009-08-31 17:42:50 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 // Return true if the bounds check succeeded
251 // Else instruct the runtime to throw an exception
Jack Palevich106006c2009-08-31 17:42:50 -0700252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 bool check() {
254 if ( ! mRef) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700255 doThrowIAE(mEnv, "array == null");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 return false;
257 }
258 if ( mOffset < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700259 doThrowIAE(mEnv, "offset < 0");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 return false;
261 }
262 mLength = mEnv->GetArrayLength(mRef) - mOffset;
263 if (mLength < mMinSize ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700264 doThrowIAE(mEnv, "length - offset < n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 return false;
266 }
267 return true;
268 }
Jack Palevich106006c2009-08-31 17:42:50 -0700269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 // Bind the array.
Jack Palevich106006c2009-08-31 17:42:50 -0700271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 void bind() {
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700273 mBase = (T*) ArrayGetter::Get(mEnv, mRef, (jboolean *) 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 mData = mBase + mOffset;
275 }
276
277 void commitChanges() {
278 mReleaseParam = 0;
279 }
Jack Palevich106006c2009-08-31 17:42:50 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 T* mData;
282 int mLength;
Jack Palevich106006c2009-08-31 17:42:50 -0700283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284private:
285 T* mBase;
286 JNIEnv* mEnv;
287 JArray mRef;
288 jint mOffset;
289 jint mMinSize;
290 int mReleaseParam;
291};
292
Hiroshi Yamauchi5b406cb2015-05-07 19:14:17 -0700293typedef ArrayHelper<jfloatArray, float, FloatArrayGetter, FloatArrayReleaser> FloatArrayHelper;
294typedef ArrayHelper<jcharArray, unsigned short, CharArrayGetter, CharArrayReleaser> UnsignedShortArrayHelper;
295typedef ArrayHelper<jintArray, int, IntArrayGetter, IntArrayReleaser> IntArrayHelper;
296typedef ArrayHelper<jbyteArray, unsigned char, ByteArrayGetter, ByteArrayReleaser> ByteArrayHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
298inline float distance2(float x, float y, float z) {
299 return x * x + y * y + z * z;
300}
301
302inline float distance(float x, float y, float z) {
303 return sqrtf(distance2(x, y, z));
304}
Jack Palevich106006c2009-08-31 17:42:50 -0700305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306static
307void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
308 jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
309 jfloatArray sphere_ref, jint sphereOffset) {
310 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
311 FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 bool checkOK = positions.check() && sphere.check();
314 if (! checkOK) {
315 return;
316 }
Jack Palevich106006c2009-08-31 17:42:50 -0700317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 positions.bind();
319 sphere.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 if ( positionsCount < 1 ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700322 doThrowIAE(env, "positionsCount < 1");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 return;
324 }
Jack Palevich106006c2009-08-31 17:42:50 -0700325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 const float* pSrc = positions.mData;
Jack Palevich106006c2009-08-31 17:42:50 -0700327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 // find bounding box
329 float x0 = *pSrc++;
330 float x1 = x0;
331 float y0 = *pSrc++;
332 float y1 = y0;
333 float z0 = *pSrc++;
334 float z1 = z0;
Jack Palevich106006c2009-08-31 17:42:50 -0700335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 for(int i = 1; i < positionsCount; i++) {
337 {
338 float x = *pSrc++;
339 if (x < x0) {
340 x0 = x;
341 }
342 else if (x > x1) {
343 x1 = x;
344 }
345 }
346 {
347 float y = *pSrc++;
348 if (y < y0) {
349 y0 = y;
350 }
351 else if (y > y1) {
352 y1 = y;
353 }
354 }
355 {
356 float z = *pSrc++;
357 if (z < z0) {
358 z0 = z;
359 }
360 else if (z > z1) {
361 z1 = z;
362 }
363 }
364 }
Jack Palevich106006c2009-08-31 17:42:50 -0700365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 // Because we know our input meshes fit pretty well into bounding boxes,
367 // just take the diagonal of the box as defining our sphere.
368 float* pSphere = sphere.mData;
369 float dx = x1 - x0;
370 float dy = y1 - y0;
371 float dz = z1 - z0;
372 *pSphere++ = x0 + dx * 0.5f;
373 *pSphere++ = y0 + dy * 0.5f;
374 *pSphere++ = z0 + dz * 0.5f;
375 *pSphere++ = distance(dx, dy, dz) * 0.5f;
Jack Palevich106006c2009-08-31 17:42:50 -0700376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 sphere.commitChanges();
378}
379
380static void normalizePlane(float* p) {
381 float rdist = 1.0f / distance(p[0], p[1], p[2]);
382 for(int i = 0; i < 4; i++) {
383 p[i] *= rdist;
384 }
385}
386
387static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
388 return x0 * x1 + y0 * y1 + z0 * z1;
389}
390
391static inline float signedDistance(const float* pPlane, float x, float y, float z) {
392 return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
393}
394
395// Return true if the sphere intersects or is inside the frustum
396
397static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
398 float x = pSphere[0];
399 float y = pSphere[1];
400 float z = pSphere[2];
401 float negRadius = -pSphere[3];
402 for (int i = 0; i < 6; i++, pFrustum += 4) {
403 if (signedDistance(pFrustum, x, y, z) <= negRadius) {
404 return false;
405 }
406 }
407 return true;
408}
409
410static void computeFrustum(const float* m, float* f) {
411 float m3 = m[3];
412 float m7 = m[7];
413 float m11 = m[11];
414 float m15 = m[15];
415 // right
416 f[0] = m3 - m[0];
417 f[1] = m7 - m[4];
418 f[2] = m11 - m[8];
419 f[3] = m15 - m[12];
420 normalizePlane(f);
421 f+= 4;
422
Jack Palevich106006c2009-08-31 17:42:50 -0700423 // left
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 f[0] = m3 + m[0];
425 f[1] = m7 + m[4];
426 f[2] = m11 + m[8];
427 f[3] = m15 + m[12];
428 normalizePlane(f);
429 f+= 4;
430
431 // top
432 f[0] = m3 - m[1];
433 f[1] = m7 - m[5];
434 f[2] = m11 - m[9];
435 f[3] = m15 - m[13];
436 normalizePlane(f);
437 f+= 4;
438
439 // bottom
440 f[0] = m3 + m[1];
441 f[1] = m7 + m[5];
442 f[2] = m11 + m[9];
443 f[3] = m15 + m[13];
444 normalizePlane(f);
445 f+= 4;
446
447 // far
448 f[0] = m3 - m[2];
449 f[1] = m7 - m[6];
450 f[2] = m11 - m[10];
451 f[3] = m15 - m[14];
452 normalizePlane(f);
453 f+= 4;
454
455 // near
456 f[0] = m3 + m[2];
457 f[1] = m7 + m[6];
458 f[2] = m11 + m[10];
459 f[3] = m15 + m[14];
460 normalizePlane(f);
461}
462
463static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000464jint util_frustumCullSpheres(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 jfloatArray mvp_ref, jint mvpOffset,
466 jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
467 jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
468 float frustum[6*4];
469 int outputCount;
470 int* pResults;
471 float* pSphere;
472 FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
473 FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
474 IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
Jack Palevich106006c2009-08-31 17:42:50 -0700475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 bool initializedOK = mvp.check() && spheres.check() && results.check();
477 if (! initializedOK) {
478 return -1;
479 }
Jack Palevich106006c2009-08-31 17:42:50 -0700480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 mvp.bind();
482 spheres.bind();
483 results.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 computeFrustum(mvp.mData, frustum);
Jack Palevich106006c2009-08-31 17:42:50 -0700486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 // Cull the spheres
Jack Palevich106006c2009-08-31 17:42:50 -0700488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 pSphere = spheres.mData;
490 pResults = results.mData;
491 outputCount = 0;
492 for(int i = 0; i < spheresCount; i++, pSphere += 4) {
493 if (sphereHitsFrustum(frustum, pSphere)) {
494 if (outputCount < resultsCapacity) {
495 *pResults++ = i;
496 }
497 outputCount++;
498 }
499 }
500 results.commitChanges();
501 return outputCount;
502}
503
504/*
505 public native int visibilityTest(float[] ws, int wsOffset,
506 float[] positions, int positionsOffset,
507 char[] indices, int indicesOffset, int indexCount);
508 */
509
510static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000511jint util_visibilityTest(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 jfloatArray ws_ref, jint wsOffset,
513 jfloatArray positions_ref, jint positionsOffset,
514 jcharArray indices_ref, jint indicesOffset, jint indexCount) {
Jack Palevich106006c2009-08-31 17:42:50 -0700515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
517 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
518 UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
Jack Palevich106006c2009-08-31 17:42:50 -0700519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 bool checkOK = ws.check() && positions.check() && indices.check();
521 if (! checkOK) {
522 // Return value will be ignored, because an exception has been thrown.
523 return -1;
524 }
Jack Palevich106006c2009-08-31 17:42:50 -0700525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 if (indices.mLength < indexCount) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700527 doThrowIAE(env, "length < offset + indexCount");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 return -1;
529 }
Jack Palevich106006c2009-08-31 17:42:50 -0700530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 ws.bind();
532 positions.bind();
533 indices.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 return visibilityTest(ws.mData,
536 positions.mData, positions.mLength,
537 indices.mData, indexCount);
538}
539
540#define I(_i, _j) ((_j)+ 4*(_i))
541
542static
543void multiplyMM(float* r, const float* lhs, const float* rhs)
544{
545 for (int i=0 ; i<4 ; i++) {
Dan Albert46d84442014-11-18 16:07:51 -0800546 const float rhs_i0 = rhs[ I(i,0) ];
547 float ri0 = lhs[ I(0,0) ] * rhs_i0;
548 float ri1 = lhs[ I(0,1) ] * rhs_i0;
549 float ri2 = lhs[ I(0,2) ] * rhs_i0;
550 float ri3 = lhs[ I(0,3) ] * rhs_i0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 for (int j=1 ; j<4 ; j++) {
Dan Albert46d84442014-11-18 16:07:51 -0800552 const float rhs_ij = rhs[ I(i,j) ];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 ri0 += lhs[ I(j,0) ] * rhs_ij;
554 ri1 += lhs[ I(j,1) ] * rhs_ij;
555 ri2 += lhs[ I(j,2) ] * rhs_ij;
556 ri3 += lhs[ I(j,3) ] * rhs_ij;
557 }
558 r[ I(i,0) ] = ri0;
559 r[ I(i,1) ] = ri1;
560 r[ I(i,2) ] = ri2;
561 r[ I(i,3) ] = ri3;
562 }
563}
564
565static
566void util_multiplyMM(JNIEnv *env, jclass clazz,
567 jfloatArray result_ref, jint resultOffset,
568 jfloatArray lhs_ref, jint lhsOffset,
569 jfloatArray rhs_ref, jint rhsOffset) {
570
571 FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
572 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
573 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
Jack Palevich106006c2009-08-31 17:42:50 -0700574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 bool checkOK = resultMat.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 if ( !checkOK ) {
578 return;
579 }
Jack Palevich106006c2009-08-31 17:42:50 -0700580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 resultMat.bind();
582 lhs.bind();
583 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 resultMat.commitChanges();
588}
589
590static
591void multiplyMV(float* r, const float* lhs, const float* rhs)
592{
593 mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
594}
595
596static
597void util_multiplyMV(JNIEnv *env, jclass clazz,
598 jfloatArray result_ref, jint resultOffset,
599 jfloatArray lhs_ref, jint lhsOffset,
600 jfloatArray rhs_ref, jint rhsOffset) {
601
602 FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
603 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
604 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 bool checkOK = resultV.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 if ( !checkOK ) {
609 return;
610 }
Jack Palevich106006c2009-08-31 17:42:50 -0700611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 resultV.bind();
613 lhs.bind();
614 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 multiplyMV(resultV.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 resultV.commitChanges();
619}
620
621// ---------------------------------------------------------------------------
622
Mike Reed1103b322014-07-08 12:36:44 -0400623static int checkFormat(SkColorType colorType, int format, int type)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624{
Mike Reed1103b322014-07-08 12:36:44 -0400625 switch(colorType) {
Mike Reed1103b322014-07-08 12:36:44 -0400626 case kN32_SkColorType:
627 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 if (type == GL_UNSIGNED_BYTE)
629 return 0;
Mike Reed1103b322014-07-08 12:36:44 -0400630 case kARGB_4444_SkColorType:
631 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 switch (type) {
633 case GL_UNSIGNED_SHORT_4_4_4_4:
634 case GL_UNSIGNED_SHORT_5_6_5:
635 case GL_UNSIGNED_SHORT_5_5_5_1:
636 return 0;
637 case GL_UNSIGNED_BYTE:
638 if (format == GL_LUMINANCE_ALPHA)
639 return 0;
640 }
641 break;
642 default:
643 break;
644 }
645 return -1;
646}
647
Mike Reed1103b322014-07-08 12:36:44 -0400648static int getInternalFormat(SkColorType colorType)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649{
Mike Reed1103b322014-07-08 12:36:44 -0400650 switch(colorType) {
651 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 return GL_ALPHA;
Mike Reed1103b322014-07-08 12:36:44 -0400653 case kARGB_4444_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400655 case kN32_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400657 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 return GL_RGB;
659 default:
660 return -1;
661 }
662}
663
Mike Reed1103b322014-07-08 12:36:44 -0400664static int getType(SkColorType colorType)
Jack Palevich708c17b2009-03-24 21:05:22 -0700665{
Mike Reed1103b322014-07-08 12:36:44 -0400666 switch(colorType) {
667 case kAlpha_8_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700668 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400669 case kARGB_4444_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700670 return GL_UNSIGNED_SHORT_4_4_4_4;
Mike Reed1103b322014-07-08 12:36:44 -0400671 case kN32_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700672 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400673 case kRGB_565_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700674 return GL_UNSIGNED_SHORT_5_6_5;
675 default:
676 return -1;
677 }
678}
679
680static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
681 jobject jbitmap)
682{
John Recked207b92015-04-10 13:52:57 -0700683 SkBitmap nativeBitmap;
684 GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
685 return getInternalFormat(nativeBitmap.colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700686}
687
688static jint util_getType(JNIEnv *env, jclass clazz,
689 jobject jbitmap)
690{
John Recked207b92015-04-10 13:52:57 -0700691 SkBitmap nativeBitmap;
692 GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
693 return getType(nativeBitmap.colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700694}
695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696static jint util_texImage2D(JNIEnv *env, jclass clazz,
697 jint target, jint level, jint internalformat,
698 jobject jbitmap, jint type, jint border)
699{
John Recked207b92015-04-10 13:52:57 -0700700 SkBitmap bitmap;
701 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400702 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 if (internalformat < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400704 internalformat = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
Jack Palevich708c17b2009-03-24 21:05:22 -0700706 if (type < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400707 type = getType(colorType);
Jack Palevich708c17b2009-03-24 21:05:22 -0700708 }
Mike Reed1103b322014-07-08 12:36:44 -0400709 int err = checkFormat(colorType, internalformat, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700711 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 const int w = bitmap.width();
713 const int h = bitmap.height();
714 const void* p = bitmap.getPixels();
715 if (internalformat == GL_PALETTE8_RGBA8_OES) {
Mike Reed81397c42017-07-18 17:04:16 -0400716 err = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 } else {
718 glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 return err;
721}
722
723static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
724 jint target, jint level, jint xoffset, jint yoffset,
725 jobject jbitmap, jint format, jint type)
726{
John Recked207b92015-04-10 13:52:57 -0700727 SkBitmap bitmap;
728 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400729 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 if (format < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400731 format = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 if (format == GL_PALETTE8_RGBA8_OES)
733 return -1; // glCompressedTexSubImage2D() not supported
734 }
Mike Reed1103b322014-07-08 12:36:44 -0400735 int err = checkFormat(colorType, format, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700737 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 const int w = bitmap.width();
739 const int h = bitmap.height();
740 const void* p = bitmap.getPixels();
741 glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 return 0;
743}
744
745/*
Jack Palevicha6276fd2009-12-28 19:31:43 +0800746 * ETC1 methods.
747 */
748
749static jclass nioAccessClass;
750static jclass bufferClass;
751static jmethodID getBasePointerID;
752static jmethodID getBaseArrayID;
753static jmethodID getBaseArrayOffsetID;
754static jfieldID positionID;
755static jfieldID limitID;
756static jfieldID elementSizeShiftID;
757
758/* Cache method IDs each time the class is loaded. */
759
760static void
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800761nativeClassInitBuffer(JNIEnv *env)
Jack Palevicha6276fd2009-12-28 19:31:43 +0800762{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800763 jclass nioAccessClassLocal = FindClassOrDie(env, "java/nio/NIOAccess");
764 nioAccessClass = MakeGlobalRefOrDie(env, nioAccessClassLocal);
765 getBasePointerID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800766 "getBasePointer", "(Ljava/nio/Buffer;)J");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800767 getBaseArrayID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800768 "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800769 getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800770 "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800771
772 jclass bufferClassLocal = FindClassOrDie(env, "java/nio/Buffer");
773 bufferClass = MakeGlobalRefOrDie(env, bufferClassLocal);
774 positionID = GetFieldIDOrDie(env, bufferClass, "position", "I");
775 limitID = GetFieldIDOrDie(env, bufferClass, "limit", "I");
776 elementSizeShiftID = GetFieldIDOrDie(env, bufferClass, "_elementSizeShift", "I");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800777}
778
779static void *
780getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
781{
782 jint position;
783 jint limit;
784 jint elementSizeShift;
785 jlong pointer;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800786
787 position = _env->GetIntField(buffer, positionID);
788 limit = _env->GetIntField(buffer, limitID);
789 elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
790 *remaining = (limit - position) << elementSizeShift;
791 pointer = _env->CallStaticLongMethod(nioAccessClass,
792 getBasePointerID, buffer);
793 if (pointer != 0L) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000794 return reinterpret_cast<void *>(pointer);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800795 }
796 return NULL;
797}
798
799class BufferHelper {
800public:
801 BufferHelper(JNIEnv *env, jobject buffer) {
802 mEnv = env;
803 mBuffer = buffer;
804 mData = NULL;
805 mRemaining = 0;
806 }
807
808 bool checkPointer(const char* errorMessage) {
809 if (mBuffer) {
810 mData = getPointer(mEnv, mBuffer, &mRemaining);
811 if (mData == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700812 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800813 }
814 return mData != NULL;
815 } else {
Elliott Hughes8451b252011-04-07 19:17:57 -0700816 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800817 return false;
818 }
819 }
820
821 inline void* getData() {
822 return mData;
823 }
824
825 inline jint remaining() {
826 return mRemaining;
827 }
828
829private:
830 JNIEnv* mEnv;
831 jobject mBuffer;
832 void* mData;
833 jint mRemaining;
834};
835
836/**
837 * Encode a block of pixels.
838 *
839 * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
840 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
841 * value of pixel (x, y).
842 *
843 * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
844 * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
845 *
846 * @param out an ETC1 compressed version of the data.
847 *
848 */
849static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
850 jobject in, jint validPixelMask, jobject out) {
851 if (validPixelMask < 0 || validPixelMask > 15) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700852 doThrowIAE(env, "validPixelMask");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800853 return;
854 }
855 BufferHelper inB(env, in);
856 BufferHelper outB(env, out);
857 if (inB.checkPointer("in") && outB.checkPointer("out")) {
858 if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700859 doThrowIAE(env, "in's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800860 } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700861 doThrowIAE(env, "out's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800862 } else {
863 etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
864 (etc1_byte*) outB.getData());
865 }
866 }
867}
868
869/**
870 * Decode a block of pixels.
871 *
872 * @param in an ETC1 compressed version of the data.
873 *
874 * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
875 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
876 * value of pixel (x, y).
877 */
878static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
879 jobject in, jobject out){
880 BufferHelper inB(env, in);
881 BufferHelper outB(env, out);
882 if (inB.checkPointer("in") && outB.checkPointer("out")) {
883 if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700884 doThrowIAE(env, "in's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800885 } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700886 doThrowIAE(env, "out's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800887 } else {
888 etc1_decode_block((etc1_byte*) inB.getData(),
889 (etc1_byte*) outB.getData());
890 }
891 }
892}
893
894/**
895 * Return the size of the encoded image data (does not include size of PKM header).
896 */
897static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
898 jint width, jint height) {
899 return etc1_get_encoded_data_size(width, height);
900}
901
902/**
903 * Encode an entire image.
904 * @param in pointer to the image data. Formatted such that
905 * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
906 * @param out pointer to encoded data. Must be large enough to store entire encoded image.
907 */
908static void etc1_encodeImage(JNIEnv *env, jclass clazz,
909 jobject in, jint width, jint height,
910 jint pixelSize, jint stride, jobject out) {
911 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700912 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800913 return;
914 }
915 BufferHelper inB(env, in);
916 BufferHelper outB(env, out);
917 if (inB.checkPointer("in") && outB.checkPointer("out")) {
918 jint imageSize = stride * height;
919 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
920 if (inB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700921 doThrowIAE(env, "in's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800922 } else if (outB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700923 doThrowIAE(env, "out's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800924 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800925 etc1_encode_image((etc1_byte*) inB.getData(), width, height, pixelSize, stride,
926 (etc1_byte*) outB.getData());
Jack Palevicha6276fd2009-12-28 19:31:43 +0800927 }
928 }
929}
930
931/**
932 * Decode an entire image.
933 * @param in the encoded data.
934 * @param out pointer to the image data. Will be written such that
935 * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
936 * large enough to store entire image.
937 */
938static void etc1_decodeImage(JNIEnv *env, jclass clazz,
939 jobject in, jobject out,
940 jint width, jint height,
941 jint pixelSize, jint stride) {
942 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700943 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800944 return;
945 }
946 BufferHelper inB(env, in);
947 BufferHelper outB(env, out);
948 if (inB.checkPointer("in") && outB.checkPointer("out")) {
949 jint imageSize = stride * height;
950 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
951 if (inB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700952 doThrowIAE(env, "in's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800953 } else if (outB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700954 doThrowIAE(env, "out's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800955 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800956 etc1_decode_image((etc1_byte*) inB.getData(), (etc1_byte*) outB.getData(),
957 width, height, pixelSize, stride);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800958 }
959 }
960}
961
962/**
963 * Format a PKM header
964 */
965static void etc1_formatHeader(JNIEnv *env, jclass clazz,
966 jobject header, jint width, jint height) {
967 BufferHelper headerB(env, header);
968 if (headerB.checkPointer("header") ){
969 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700970 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800971 } else {
972 etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
973 }
974 }
975}
976
977/**
978 * Check if a PKM header is correctly formatted.
979 */
980static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
981 jobject header) {
982 jboolean result = false;
983 BufferHelper headerB(env, header);
984 if (headerB.checkPointer("header") ){
985 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700986 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800987 } else {
988 result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
989 }
990 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000991 return result ? JNI_TRUE : JNI_FALSE;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800992}
993
994/**
995 * Read the image width from a PKM header
996 */
997static jint etc1_getWidth(JNIEnv *env, jclass clazz,
998 jobject header) {
999 jint result = 0;
1000 BufferHelper headerB(env, header);
1001 if (headerB.checkPointer("header") ){
1002 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001003 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001004 } else {
1005 result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
1006 }
1007 }
1008 return result;
1009}
1010
1011/**
1012 * Read the image height from a PKM header
1013 */
Ashok Bhat36bef0b2014-01-20 20:08:01 +00001014static jint etc1_getHeight(JNIEnv *env, jclass clazz,
Jack Palevicha6276fd2009-12-28 19:31:43 +08001015 jobject header) {
1016 jint result = 0;
1017 BufferHelper headerB(env, header);
1018 if (headerB.checkPointer("header") ){
1019 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001020 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001021 } else {
1022 result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
1023 }
1024 }
1025 return result;
1026}
1027
1028/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 * JNI registration
1030 */
1031
Daniel Micay76f6a862015-09-19 17:31:01 -04001032static const JNINativeMethod gMatrixMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001033 { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
1034 { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035};
1036
Daniel Micay76f6a862015-09-19 17:31:01 -04001037static const JNINativeMethod gVisibilityMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001038 { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
Jack Palevich106006c2009-08-31 17:42:50 -07001040 { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041};
1042
Daniel Micay76f6a862015-09-19 17:31:01 -04001043static const JNINativeMethod gUtilsMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001044 { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
1045 { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
1046 { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
1047 { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048};
1049
Daniel Micay76f6a862015-09-19 17:31:01 -04001050static const JNINativeMethod gEtc1Methods[] = {
Jack Palevicha6276fd2009-12-28 19:31:43 +08001051 { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
1052 { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
1053 { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
1054 { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
1055 { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
1056 { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
1057 { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
1058 { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
1059 { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
1060};
1061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062typedef struct _ClassRegistrationInfo {
1063 const char* classPath;
Daniel Micay76f6a862015-09-19 17:31:01 -04001064 const JNINativeMethod* methods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 size_t methodCount;
1066} ClassRegistrationInfo;
1067
Daniel Micay76f6a862015-09-19 17:31:01 -04001068static const ClassRegistrationInfo gClasses[] = {
Elliott Hughes8451b252011-04-07 19:17:57 -07001069 {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
1070 {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
1071 {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
1072 {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073};
1074
1075int register_android_opengl_classes(JNIEnv* env)
1076{
Jack Palevicha6276fd2009-12-28 19:31:43 +08001077 nativeClassInitBuffer(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 int result = 0;
1079 for (int i = 0; i < NELEM(gClasses); i++) {
Daniel Micay76f6a862015-09-19 17:31:01 -04001080 const ClassRegistrationInfo* cri = &gClasses[i];
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001081 result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083 return result;
1084}
1085
1086} // namespace android