blob: 5c2d0d0bb5cb734126acbe55a09318ec356401aa [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
153template<class JArray, class T>
154class ArrayHelper {
155public:
156 ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
157 mEnv = env;
158 mRef = ref;
159 mOffset = offset;
160 mMinSize = minSize;
161 mBase = 0;
162 mReleaseParam = JNI_ABORT;
163 }
164
165 ~ArrayHelper() {
166 if (mBase) {
167 mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
168 }
169 }
Jack Palevich106006c2009-08-31 17:42:50 -0700170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 // We seperate the bounds check from the initialization because we want to
172 // be able to bounds-check multiple arrays, and we can't throw an exception
173 // after we've called GetPrimitiveArrayCritical.
Jack Palevich106006c2009-08-31 17:42:50 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 // Return true if the bounds check succeeded
176 // Else instruct the runtime to throw an exception
Jack Palevich106006c2009-08-31 17:42:50 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 bool check() {
179 if ( ! mRef) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700180 doThrowIAE(mEnv, "array == null");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return false;
182 }
183 if ( mOffset < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700184 doThrowIAE(mEnv, "offset < 0");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 return false;
186 }
187 mLength = mEnv->GetArrayLength(mRef) - mOffset;
188 if (mLength < mMinSize ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700189 doThrowIAE(mEnv, "length - offset < n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 return false;
191 }
192 return true;
193 }
Jack Palevich106006c2009-08-31 17:42:50 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 // Bind the array.
Jack Palevich106006c2009-08-31 17:42:50 -0700196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 void bind() {
198 mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
199 mData = mBase + mOffset;
200 }
201
202 void commitChanges() {
203 mReleaseParam = 0;
204 }
Jack Palevich106006c2009-08-31 17:42:50 -0700205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 T* mData;
207 int mLength;
Jack Palevich106006c2009-08-31 17:42:50 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209private:
210 T* mBase;
211 JNIEnv* mEnv;
212 JArray mRef;
213 jint mOffset;
214 jint mMinSize;
215 int mReleaseParam;
216};
217
218typedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
219typedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
220typedef ArrayHelper<jintArray, int> IntArrayHelper;
221typedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
222
223inline float distance2(float x, float y, float z) {
224 return x * x + y * y + z * z;
225}
226
227inline float distance(float x, float y, float z) {
228 return sqrtf(distance2(x, y, z));
229}
Jack Palevich106006c2009-08-31 17:42:50 -0700230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231static
232void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
233 jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
234 jfloatArray sphere_ref, jint sphereOffset) {
235 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
236 FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 bool checkOK = positions.check() && sphere.check();
239 if (! checkOK) {
240 return;
241 }
Jack Palevich106006c2009-08-31 17:42:50 -0700242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 positions.bind();
244 sphere.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 if ( positionsCount < 1 ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700247 doThrowIAE(env, "positionsCount < 1");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 return;
249 }
Jack Palevich106006c2009-08-31 17:42:50 -0700250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 const float* pSrc = positions.mData;
Jack Palevich106006c2009-08-31 17:42:50 -0700252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 // find bounding box
254 float x0 = *pSrc++;
255 float x1 = x0;
256 float y0 = *pSrc++;
257 float y1 = y0;
258 float z0 = *pSrc++;
259 float z1 = z0;
Jack Palevich106006c2009-08-31 17:42:50 -0700260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 for(int i = 1; i < positionsCount; i++) {
262 {
263 float x = *pSrc++;
264 if (x < x0) {
265 x0 = x;
266 }
267 else if (x > x1) {
268 x1 = x;
269 }
270 }
271 {
272 float y = *pSrc++;
273 if (y < y0) {
274 y0 = y;
275 }
276 else if (y > y1) {
277 y1 = y;
278 }
279 }
280 {
281 float z = *pSrc++;
282 if (z < z0) {
283 z0 = z;
284 }
285 else if (z > z1) {
286 z1 = z;
287 }
288 }
289 }
Jack Palevich106006c2009-08-31 17:42:50 -0700290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 // Because we know our input meshes fit pretty well into bounding boxes,
292 // just take the diagonal of the box as defining our sphere.
293 float* pSphere = sphere.mData;
294 float dx = x1 - x0;
295 float dy = y1 - y0;
296 float dz = z1 - z0;
297 *pSphere++ = x0 + dx * 0.5f;
298 *pSphere++ = y0 + dy * 0.5f;
299 *pSphere++ = z0 + dz * 0.5f;
300 *pSphere++ = distance(dx, dy, dz) * 0.5f;
Jack Palevich106006c2009-08-31 17:42:50 -0700301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 sphere.commitChanges();
303}
304
305static void normalizePlane(float* p) {
306 float rdist = 1.0f / distance(p[0], p[1], p[2]);
307 for(int i = 0; i < 4; i++) {
308 p[i] *= rdist;
309 }
310}
311
312static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
313 return x0 * x1 + y0 * y1 + z0 * z1;
314}
315
316static inline float signedDistance(const float* pPlane, float x, float y, float z) {
317 return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
318}
319
320// Return true if the sphere intersects or is inside the frustum
321
322static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
323 float x = pSphere[0];
324 float y = pSphere[1];
325 float z = pSphere[2];
326 float negRadius = -pSphere[3];
327 for (int i = 0; i < 6; i++, pFrustum += 4) {
328 if (signedDistance(pFrustum, x, y, z) <= negRadius) {
329 return false;
330 }
331 }
332 return true;
333}
334
335static void computeFrustum(const float* m, float* f) {
336 float m3 = m[3];
337 float m7 = m[7];
338 float m11 = m[11];
339 float m15 = m[15];
340 // right
341 f[0] = m3 - m[0];
342 f[1] = m7 - m[4];
343 f[2] = m11 - m[8];
344 f[3] = m15 - m[12];
345 normalizePlane(f);
346 f+= 4;
347
Jack Palevich106006c2009-08-31 17:42:50 -0700348 // left
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 f[0] = m3 + m[0];
350 f[1] = m7 + m[4];
351 f[2] = m11 + m[8];
352 f[3] = m15 + m[12];
353 normalizePlane(f);
354 f+= 4;
355
356 // top
357 f[0] = m3 - m[1];
358 f[1] = m7 - m[5];
359 f[2] = m11 - m[9];
360 f[3] = m15 - m[13];
361 normalizePlane(f);
362 f+= 4;
363
364 // bottom
365 f[0] = m3 + m[1];
366 f[1] = m7 + m[5];
367 f[2] = m11 + m[9];
368 f[3] = m15 + m[13];
369 normalizePlane(f);
370 f+= 4;
371
372 // far
373 f[0] = m3 - m[2];
374 f[1] = m7 - m[6];
375 f[2] = m11 - m[10];
376 f[3] = m15 - m[14];
377 normalizePlane(f);
378 f+= 4;
379
380 // near
381 f[0] = m3 + m[2];
382 f[1] = m7 + m[6];
383 f[2] = m11 + m[10];
384 f[3] = m15 + m[14];
385 normalizePlane(f);
386}
387
388static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000389jint util_frustumCullSpheres(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 jfloatArray mvp_ref, jint mvpOffset,
391 jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
392 jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
393 float frustum[6*4];
394 int outputCount;
395 int* pResults;
396 float* pSphere;
397 FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
398 FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
399 IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
Jack Palevich106006c2009-08-31 17:42:50 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 bool initializedOK = mvp.check() && spheres.check() && results.check();
402 if (! initializedOK) {
403 return -1;
404 }
Jack Palevich106006c2009-08-31 17:42:50 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 mvp.bind();
407 spheres.bind();
408 results.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 computeFrustum(mvp.mData, frustum);
Jack Palevich106006c2009-08-31 17:42:50 -0700411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 // Cull the spheres
Jack Palevich106006c2009-08-31 17:42:50 -0700413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 pSphere = spheres.mData;
415 pResults = results.mData;
416 outputCount = 0;
417 for(int i = 0; i < spheresCount; i++, pSphere += 4) {
418 if (sphereHitsFrustum(frustum, pSphere)) {
419 if (outputCount < resultsCapacity) {
420 *pResults++ = i;
421 }
422 outputCount++;
423 }
424 }
425 results.commitChanges();
426 return outputCount;
427}
428
429/*
430 public native int visibilityTest(float[] ws, int wsOffset,
431 float[] positions, int positionsOffset,
432 char[] indices, int indicesOffset, int indexCount);
433 */
434
435static
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000436jint util_visibilityTest(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 jfloatArray ws_ref, jint wsOffset,
438 jfloatArray positions_ref, jint positionsOffset,
439 jcharArray indices_ref, jint indicesOffset, jint indexCount) {
Jack Palevich106006c2009-08-31 17:42:50 -0700440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
442 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
443 UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
Jack Palevich106006c2009-08-31 17:42:50 -0700444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 bool checkOK = ws.check() && positions.check() && indices.check();
446 if (! checkOK) {
447 // Return value will be ignored, because an exception has been thrown.
448 return -1;
449 }
Jack Palevich106006c2009-08-31 17:42:50 -0700450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 if (indices.mLength < indexCount) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700452 doThrowIAE(env, "length < offset + indexCount");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 return -1;
454 }
Jack Palevich106006c2009-08-31 17:42:50 -0700455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 ws.bind();
457 positions.bind();
458 indices.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 return visibilityTest(ws.mData,
461 positions.mData, positions.mLength,
462 indices.mData, indexCount);
463}
464
465#define I(_i, _j) ((_j)+ 4*(_i))
466
467static
468void multiplyMM(float* r, const float* lhs, const float* rhs)
469{
470 for (int i=0 ; i<4 ; i++) {
Dan Albert46d84442014-11-18 16:07:51 -0800471 const float rhs_i0 = rhs[ I(i,0) ];
472 float ri0 = lhs[ I(0,0) ] * rhs_i0;
473 float ri1 = lhs[ I(0,1) ] * rhs_i0;
474 float ri2 = lhs[ I(0,2) ] * rhs_i0;
475 float ri3 = lhs[ I(0,3) ] * rhs_i0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 for (int j=1 ; j<4 ; j++) {
Dan Albert46d84442014-11-18 16:07:51 -0800477 const float rhs_ij = rhs[ I(i,j) ];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 ri0 += lhs[ I(j,0) ] * rhs_ij;
479 ri1 += lhs[ I(j,1) ] * rhs_ij;
480 ri2 += lhs[ I(j,2) ] * rhs_ij;
481 ri3 += lhs[ I(j,3) ] * rhs_ij;
482 }
483 r[ I(i,0) ] = ri0;
484 r[ I(i,1) ] = ri1;
485 r[ I(i,2) ] = ri2;
486 r[ I(i,3) ] = ri3;
487 }
488}
489
490static
491void util_multiplyMM(JNIEnv *env, jclass clazz,
492 jfloatArray result_ref, jint resultOffset,
493 jfloatArray lhs_ref, jint lhsOffset,
494 jfloatArray rhs_ref, jint rhsOffset) {
495
496 FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
497 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
498 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
Jack Palevich106006c2009-08-31 17:42:50 -0700499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 bool checkOK = resultMat.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 if ( !checkOK ) {
503 return;
504 }
Jack Palevich106006c2009-08-31 17:42:50 -0700505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 resultMat.bind();
507 lhs.bind();
508 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 resultMat.commitChanges();
513}
514
515static
516void multiplyMV(float* r, const float* lhs, const float* rhs)
517{
518 mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
519}
520
521static
522void util_multiplyMV(JNIEnv *env, jclass clazz,
523 jfloatArray result_ref, jint resultOffset,
524 jfloatArray lhs_ref, jint lhsOffset,
525 jfloatArray rhs_ref, jint rhsOffset) {
526
527 FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
528 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
529 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 bool checkOK = resultV.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 if ( !checkOK ) {
534 return;
535 }
Jack Palevich106006c2009-08-31 17:42:50 -0700536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 resultV.bind();
538 lhs.bind();
539 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 multiplyMV(resultV.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 resultV.commitChanges();
544}
545
546// ---------------------------------------------------------------------------
547
Siva Velusamy64d10a12012-03-09 14:21:28 -0800548extern void setGLDebugLevel(int level);
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800549void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
Siva Velusamy64d10a12012-03-09 14:21:28 -0800550{
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800551 setGLDebugLevel(level);
Siva Velusamy64d10a12012-03-09 14:21:28 -0800552}
553
Mike Reed1103b322014-07-08 12:36:44 -0400554static int checkFormat(SkColorType colorType, int format, int type)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555{
Mike Reed1103b322014-07-08 12:36:44 -0400556 switch(colorType) {
557 case kIndex_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 if (format == GL_PALETTE8_RGBA8_OES)
559 return 0;
Mike Reed1103b322014-07-08 12:36:44 -0400560 case kN32_SkColorType:
561 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 if (type == GL_UNSIGNED_BYTE)
563 return 0;
Mike Reed1103b322014-07-08 12:36:44 -0400564 case kARGB_4444_SkColorType:
565 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 switch (type) {
567 case GL_UNSIGNED_SHORT_4_4_4_4:
568 case GL_UNSIGNED_SHORT_5_6_5:
569 case GL_UNSIGNED_SHORT_5_5_5_1:
570 return 0;
571 case GL_UNSIGNED_BYTE:
572 if (format == GL_LUMINANCE_ALPHA)
573 return 0;
574 }
575 break;
576 default:
577 break;
578 }
579 return -1;
580}
581
Mike Reed1103b322014-07-08 12:36:44 -0400582static int getInternalFormat(SkColorType colorType)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583{
Mike Reed1103b322014-07-08 12:36:44 -0400584 switch(colorType) {
585 case kAlpha_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return GL_ALPHA;
Mike Reed1103b322014-07-08 12:36:44 -0400587 case kARGB_4444_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400589 case kN32_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 return GL_RGBA;
Mike Reed1103b322014-07-08 12:36:44 -0400591 case kIndex_8_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 return GL_PALETTE8_RGBA8_OES;
Mike Reed1103b322014-07-08 12:36:44 -0400593 case kRGB_565_SkColorType:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 return GL_RGB;
595 default:
596 return -1;
597 }
598}
599
Mike Reed1103b322014-07-08 12:36:44 -0400600static int getType(SkColorType colorType)
Jack Palevich708c17b2009-03-24 21:05:22 -0700601{
Mike Reed1103b322014-07-08 12:36:44 -0400602 switch(colorType) {
603 case kAlpha_8_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700604 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400605 case kARGB_4444_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700606 return GL_UNSIGNED_SHORT_4_4_4_4;
Mike Reed1103b322014-07-08 12:36:44 -0400607 case kN32_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700608 return GL_UNSIGNED_BYTE;
Mike Reed1103b322014-07-08 12:36:44 -0400609 case kIndex_8_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700610 return -1; // No type for compressed data.
Mike Reed1103b322014-07-08 12:36:44 -0400611 case kRGB_565_SkColorType:
Jack Palevich708c17b2009-03-24 21:05:22 -0700612 return GL_UNSIGNED_SHORT_5_6_5;
613 default:
614 return -1;
615 }
616}
617
618static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
619 jobject jbitmap)
620{
John Reckedc22fb2015-04-20 22:06:31 +0000621 SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
622 return getInternalFormat(nativeBitmap->colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700623}
624
625static jint util_getType(JNIEnv *env, jclass clazz,
626 jobject jbitmap)
627{
John Reckedc22fb2015-04-20 22:06:31 +0000628 SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
629 return getType(nativeBitmap->colorType());
Jack Palevich708c17b2009-03-24 21:05:22 -0700630}
631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632static jint util_texImage2D(JNIEnv *env, jclass clazz,
633 jint target, jint level, jint internalformat,
634 jobject jbitmap, jint type, jint border)
635{
John Reckedc22fb2015-04-20 22:06:31 +0000636 SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
637 const SkBitmap& bitmap(*nativeBitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400638 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 if (internalformat < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400640 internalformat = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
Jack Palevich708c17b2009-03-24 21:05:22 -0700642 if (type < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400643 type = getType(colorType);
Jack Palevich708c17b2009-03-24 21:05:22 -0700644 }
Mike Reed1103b322014-07-08 12:36:44 -0400645 int err = checkFormat(colorType, internalformat, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700647 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 bitmap.lockPixels();
649 const int w = bitmap.width();
650 const int h = bitmap.height();
651 const void* p = bitmap.getPixels();
652 if (internalformat == GL_PALETTE8_RGBA8_OES) {
653 if (sizeof(SkPMColor) != sizeof(uint32_t)) {
654 err = -1;
655 goto error;
656 }
657 const size_t size = bitmap.getSize();
658 const size_t palette_size = 256*sizeof(SkPMColor);
Jack Palevich106006c2009-08-31 17:42:50 -0700659 const size_t imageSize = size + palette_size;
660 void* const data = malloc(imageSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 if (data) {
662 void* const pixels = (char*)data + palette_size;
663 SkColorTable* ctable = bitmap.getColorTable();
Mike Reed71487eb2014-11-19 16:13:20 -0500664 memcpy(data, ctable->readColors(), ctable->count() * sizeof(SkPMColor));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 memcpy(pixels, p, size);
Jack Palevich106006c2009-08-31 17:42:50 -0700666 glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 free(data);
668 } else {
669 err = -1;
670 }
671 } else {
672 glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
673 }
674error:
675 bitmap.unlockPixels();
676 return err;
677}
678
679static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
680 jint target, jint level, jint xoffset, jint yoffset,
681 jobject jbitmap, jint format, jint type)
682{
John Reckedc22fb2015-04-20 22:06:31 +0000683 SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
684 const SkBitmap& bitmap(*nativeBitmap);
Mike Reed1103b322014-07-08 12:36:44 -0400685 SkColorType colorType = bitmap.colorType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 if (format < 0) {
Mike Reed1103b322014-07-08 12:36:44 -0400687 format = getInternalFormat(colorType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 if (format == GL_PALETTE8_RGBA8_OES)
689 return -1; // glCompressedTexSubImage2D() not supported
690 }
Mike Reed1103b322014-07-08 12:36:44 -0400691 int err = checkFormat(colorType, format, type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700693 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 bitmap.lockPixels();
695 const int w = bitmap.width();
696 const int h = bitmap.height();
697 const void* p = bitmap.getPixels();
698 glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
699 bitmap.unlockPixels();
700 return 0;
701}
702
703/*
Jack Palevicha6276fd2009-12-28 19:31:43 +0800704 * ETC1 methods.
705 */
706
707static jclass nioAccessClass;
708static jclass bufferClass;
709static jmethodID getBasePointerID;
710static jmethodID getBaseArrayID;
711static jmethodID getBaseArrayOffsetID;
712static jfieldID positionID;
713static jfieldID limitID;
714static jfieldID elementSizeShiftID;
715
716/* Cache method IDs each time the class is loaded. */
717
718static void
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800719nativeClassInitBuffer(JNIEnv *env)
Jack Palevicha6276fd2009-12-28 19:31:43 +0800720{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800721 jclass nioAccessClassLocal = FindClassOrDie(env, "java/nio/NIOAccess");
722 nioAccessClass = MakeGlobalRefOrDie(env, nioAccessClassLocal);
723 getBasePointerID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800724 "getBasePointer", "(Ljava/nio/Buffer;)J");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800725 getBaseArrayID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800726 "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800727 getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, nioAccessClass,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800728 "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800729
730 jclass bufferClassLocal = FindClassOrDie(env, "java/nio/Buffer");
731 bufferClass = MakeGlobalRefOrDie(env, bufferClassLocal);
732 positionID = GetFieldIDOrDie(env, bufferClass, "position", "I");
733 limitID = GetFieldIDOrDie(env, bufferClass, "limit", "I");
734 elementSizeShiftID = GetFieldIDOrDie(env, bufferClass, "_elementSizeShift", "I");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800735}
736
737static void *
738getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
739{
740 jint position;
741 jint limit;
742 jint elementSizeShift;
743 jlong pointer;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800744
745 position = _env->GetIntField(buffer, positionID);
746 limit = _env->GetIntField(buffer, limitID);
747 elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
748 *remaining = (limit - position) << elementSizeShift;
749 pointer = _env->CallStaticLongMethod(nioAccessClass,
750 getBasePointerID, buffer);
751 if (pointer != 0L) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000752 return reinterpret_cast<void *>(pointer);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800753 }
754 return NULL;
755}
756
757class BufferHelper {
758public:
759 BufferHelper(JNIEnv *env, jobject buffer) {
760 mEnv = env;
761 mBuffer = buffer;
762 mData = NULL;
763 mRemaining = 0;
764 }
765
766 bool checkPointer(const char* errorMessage) {
767 if (mBuffer) {
768 mData = getPointer(mEnv, mBuffer, &mRemaining);
769 if (mData == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700770 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800771 }
772 return mData != NULL;
773 } else {
Elliott Hughes8451b252011-04-07 19:17:57 -0700774 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800775 return false;
776 }
777 }
778
779 inline void* getData() {
780 return mData;
781 }
782
783 inline jint remaining() {
784 return mRemaining;
785 }
786
787private:
788 JNIEnv* mEnv;
789 jobject mBuffer;
790 void* mData;
791 jint mRemaining;
792};
793
794/**
795 * Encode a block of pixels.
796 *
797 * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
798 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
799 * value of pixel (x, y).
800 *
801 * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
802 * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
803 *
804 * @param out an ETC1 compressed version of the data.
805 *
806 */
807static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
808 jobject in, jint validPixelMask, jobject out) {
809 if (validPixelMask < 0 || validPixelMask > 15) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700810 doThrowIAE(env, "validPixelMask");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800811 return;
812 }
813 BufferHelper inB(env, in);
814 BufferHelper outB(env, out);
815 if (inB.checkPointer("in") && outB.checkPointer("out")) {
816 if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700817 doThrowIAE(env, "in's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800818 } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700819 doThrowIAE(env, "out's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800820 } else {
821 etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
822 (etc1_byte*) outB.getData());
823 }
824 }
825}
826
827/**
828 * Decode a block of pixels.
829 *
830 * @param in an ETC1 compressed version of the data.
831 *
832 * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
833 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
834 * value of pixel (x, y).
835 */
836static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
837 jobject in, jobject out){
838 BufferHelper inB(env, in);
839 BufferHelper outB(env, out);
840 if (inB.checkPointer("in") && outB.checkPointer("out")) {
841 if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700842 doThrowIAE(env, "in's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800843 } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700844 doThrowIAE(env, "out's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800845 } else {
846 etc1_decode_block((etc1_byte*) inB.getData(),
847 (etc1_byte*) outB.getData());
848 }
849 }
850}
851
852/**
853 * Return the size of the encoded image data (does not include size of PKM header).
854 */
855static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
856 jint width, jint height) {
857 return etc1_get_encoded_data_size(width, height);
858}
859
860/**
861 * Encode an entire image.
862 * @param in pointer to the image data. Formatted such that
863 * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
864 * @param out pointer to encoded data. Must be large enough to store entire encoded image.
865 */
866static void etc1_encodeImage(JNIEnv *env, jclass clazz,
867 jobject in, jint width, jint height,
868 jint pixelSize, jint stride, jobject out) {
869 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700870 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800871 return;
872 }
873 BufferHelper inB(env, in);
874 BufferHelper outB(env, out);
875 if (inB.checkPointer("in") && outB.checkPointer("out")) {
876 jint imageSize = stride * height;
877 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
878 if (inB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700879 doThrowIAE(env, "in's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800880 } else if (outB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700881 doThrowIAE(env, "out's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800882 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800883 etc1_encode_image((etc1_byte*) inB.getData(), width, height, pixelSize, stride,
884 (etc1_byte*) outB.getData());
Jack Palevicha6276fd2009-12-28 19:31:43 +0800885 }
886 }
887}
888
889/**
890 * Decode an entire image.
891 * @param in the encoded data.
892 * @param out pointer to the image data. Will be written such that
893 * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
894 * large enough to store entire image.
895 */
896static void etc1_decodeImage(JNIEnv *env, jclass clazz,
897 jobject in, jobject out,
898 jint width, jint height,
899 jint pixelSize, jint stride) {
900 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700901 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800902 return;
903 }
904 BufferHelper inB(env, in);
905 BufferHelper outB(env, out);
906 if (inB.checkPointer("in") && outB.checkPointer("out")) {
907 jint imageSize = stride * height;
908 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
909 if (inB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700910 doThrowIAE(env, "in's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800911 } else if (outB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700912 doThrowIAE(env, "out's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800913 } else {
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800914 etc1_decode_image((etc1_byte*) inB.getData(), (etc1_byte*) outB.getData(),
915 width, height, pixelSize, stride);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800916 }
917 }
918}
919
920/**
921 * Format a PKM header
922 */
923static void etc1_formatHeader(JNIEnv *env, jclass clazz,
924 jobject header, jint width, jint height) {
925 BufferHelper headerB(env, header);
926 if (headerB.checkPointer("header") ){
927 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700928 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800929 } else {
930 etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
931 }
932 }
933}
934
935/**
936 * Check if a PKM header is correctly formatted.
937 */
938static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
939 jobject header) {
940 jboolean result = false;
941 BufferHelper headerB(env, header);
942 if (headerB.checkPointer("header") ){
943 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700944 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800945 } else {
946 result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
947 }
948 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000949 return result ? JNI_TRUE : JNI_FALSE;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800950}
951
952/**
953 * Read the image width from a PKM header
954 */
955static jint etc1_getWidth(JNIEnv *env, jclass clazz,
956 jobject header) {
957 jint result = 0;
958 BufferHelper headerB(env, header);
959 if (headerB.checkPointer("header") ){
960 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700961 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800962 } else {
963 result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
964 }
965 }
966 return result;
967}
968
969/**
970 * Read the image height from a PKM header
971 */
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000972static jint etc1_getHeight(JNIEnv *env, jclass clazz,
Jack Palevicha6276fd2009-12-28 19:31:43 +0800973 jobject header) {
974 jint result = 0;
975 BufferHelper headerB(env, header);
976 if (headerB.checkPointer("header") ){
977 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700978 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800979 } else {
980 result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
981 }
982 }
983 return result;
984}
985
986/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 * JNI registration
988 */
989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990static JNINativeMethod gMatrixMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -0700991 { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
992 { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993};
994
Elliott Hughes8451b252011-04-07 19:17:57 -0700995static JNINativeMethod gVisibilityMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -0700996 { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
Jack Palevich106006c2009-08-31 17:42:50 -0700998 { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999};
1000
1001static JNINativeMethod gUtilsMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001002 { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
1003 { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
1004 { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
1005 { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
Siva Velusamy0c1761b2012-12-14 17:09:06 -08001006 { "setTracingLevel", "(I)V", (void*)setTracingLevel },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007};
1008
Jack Palevicha6276fd2009-12-28 19:31:43 +08001009static JNINativeMethod gEtc1Methods[] = {
1010 { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
1011 { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
1012 { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
1013 { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
1014 { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
1015 { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
1016 { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
1017 { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
1018 { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
1019};
1020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021typedef struct _ClassRegistrationInfo {
1022 const char* classPath;
1023 JNINativeMethod* methods;
1024 size_t methodCount;
1025} ClassRegistrationInfo;
1026
1027static ClassRegistrationInfo gClasses[] = {
Elliott Hughes8451b252011-04-07 19:17:57 -07001028 {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
1029 {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
1030 {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
1031 {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032};
1033
1034int register_android_opengl_classes(JNIEnv* env)
1035{
Jack Palevicha6276fd2009-12-28 19:31:43 +08001036 nativeClassInitBuffer(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 int result = 0;
1038 for (int i = 0; i < NELEM(gClasses); i++) {
1039 ClassRegistrationInfo* cri = &gClasses[i];
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001040 result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042 return result;
1043}
1044
1045} // namespace android