blob: 48367ffb464fce8169cae96963339ebd8fa3ff70 [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"
19
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020#include <math.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <assert.h>
25#include <dlfcn.h>
26
27#include <GLES/gl.h>
Jack Palevicha6276fd2009-12-28 19:31:43 +080028#include <ETC1/etc1.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30#include <core/SkBitmap.h>
31
32#include "android_runtime/AndroidRuntime.h"
33
34#undef LOG_TAG
35#define LOG_TAG "OpenGLUtil"
36#include <utils/Log.h>
37#include "utils/misc.h"
38
39#include "poly.h"
40
41namespace android {
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043static inline
44void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
45 pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
46 pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
47 pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
48 pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
49}
50
51class MallocHelper {
52public:
53 MallocHelper() {
54 mData = 0;
55 }
Jack Palevich106006c2009-08-31 17:42:50 -070056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 ~MallocHelper() {
58 if (mData != 0) {
59 free(mData);
60 }
61 }
Jack Palevich106006c2009-08-31 17:42:50 -070062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 void* alloc(size_t size) {
64 mData = malloc(size);
65 return mData;
66 }
Jack Palevich106006c2009-08-31 17:42:50 -070067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068private:
69 void* mData;
70};
71
72#if 0
73static
74void
75print_poly(const char* label, Poly* pPoly) {
Steve Block6215d3f2012-01-04 20:05:49 +000076 ALOGI("%s: %d verts", label, pPoly->n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 for(int i = 0; i < pPoly->n; i++) {
78 Poly_vert* pV = & pPoly->vert[i];
Steve Block6215d3f2012-01-04 20:05:49 +000079 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 -080080 }
81}
82#endif
83
84static
85int visibilityTest(float* pWS, float* pPositions, int positionsLength,
86 unsigned short* pIndices, int indexCount) {
87 MallocHelper mallocHelper;
88 int result = POLY_CLIP_OUT;
89 float* pTransformed = 0;
90 int transformedIndexCount = 0;
Jack Palevich106006c2009-08-31 17:42:50 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 if ( indexCount < 3 ) {
93 return POLY_CLIP_OUT;
94 }
Jack Palevich106006c2009-08-31 17:42:50 -070095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 // Find out how many vertices we need to transform
97 // We transform every vertex between the min and max indices, inclusive.
98 // This is OK for the data sets we expect to use with this function, but
99 // for other loads it might be better to use a more sophisticated vertex
100 // cache of some sort.
Jack Palevich106006c2009-08-31 17:42:50 -0700101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 int minIndex = 65536;
103 int maxIndex = -1;
104 for(int i = 0; i < indexCount; i++) {
105 int index = pIndices[i];
106 if ( index < minIndex ) {
107 minIndex = index;
108 }
109 if ( index > maxIndex ) {
110 maxIndex = index;
111 }
112 }
Jack Palevich106006c2009-08-31 17:42:50 -0700113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 if ( maxIndex * 3 > positionsLength) {
115 return -1;
116 }
Jack Palevich106006c2009-08-31 17:42:50 -0700117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 transformedIndexCount = maxIndex - minIndex + 1;
119 pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
Jack Palevich106006c2009-08-31 17:42:50 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 if (pTransformed == 0 ) {
122 return -2;
123 }
Jack Palevich106006c2009-08-31 17:42:50 -0700124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 // Transform the vertices
126 {
127 const float* pSrc = pPositions + 3 * minIndex;
128 float* pDst = pTransformed;
129 for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
130 mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
131 }
132 }
Jack Palevich106006c2009-08-31 17:42:50 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 // Clip the triangles
Jack Palevich106006c2009-08-31 17:42:50 -0700135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 Poly poly;
137 float* pDest = & poly.vert[0].sx;
138 for (int i = 0; i < indexCount; i += 3) {
139 poly.n = 3;
140 memcpy(pDest , pTransformed + 4 * (pIndices[i ] - minIndex), 4 * sizeof(float));
141 memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
142 memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
143 result = poly_clip_to_frustum(&poly);
144 if ( result != POLY_CLIP_OUT) {
145 return result;
146 }
147 }
148
149 return result;
150}
151
Elliott Hughes8451b252011-04-07 19:17:57 -0700152static void doThrowIAE(JNIEnv* env, const char* msg) {
153 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
154}
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156template<class JArray, class T>
157class ArrayHelper {
158public:
159 ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
160 mEnv = env;
161 mRef = ref;
162 mOffset = offset;
163 mMinSize = minSize;
164 mBase = 0;
165 mReleaseParam = JNI_ABORT;
166 }
167
168 ~ArrayHelper() {
169 if (mBase) {
170 mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
171 }
172 }
Jack Palevich106006c2009-08-31 17:42:50 -0700173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 // We seperate the bounds check from the initialization because we want to
175 // be able to bounds-check multiple arrays, and we can't throw an exception
176 // after we've called GetPrimitiveArrayCritical.
Jack Palevich106006c2009-08-31 17:42:50 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 // Return true if the bounds check succeeded
179 // Else instruct the runtime to throw an exception
Jack Palevich106006c2009-08-31 17:42:50 -0700180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 bool check() {
182 if ( ! mRef) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700183 doThrowIAE(mEnv, "array == null");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 return false;
185 }
186 if ( mOffset < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700187 doThrowIAE(mEnv, "offset < 0");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 return false;
189 }
190 mLength = mEnv->GetArrayLength(mRef) - mOffset;
191 if (mLength < mMinSize ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700192 doThrowIAE(mEnv, "length - offset < n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 return false;
194 }
195 return true;
196 }
Jack Palevich106006c2009-08-31 17:42:50 -0700197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 // Bind the array.
Jack Palevich106006c2009-08-31 17:42:50 -0700199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 void bind() {
201 mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
202 mData = mBase + mOffset;
203 }
204
205 void commitChanges() {
206 mReleaseParam = 0;
207 }
Jack Palevich106006c2009-08-31 17:42:50 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 T* mData;
210 int mLength;
Jack Palevich106006c2009-08-31 17:42:50 -0700211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212private:
213 T* mBase;
214 JNIEnv* mEnv;
215 JArray mRef;
216 jint mOffset;
217 jint mMinSize;
218 int mReleaseParam;
219};
220
221typedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
222typedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
223typedef ArrayHelper<jintArray, int> IntArrayHelper;
224typedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
225
226inline float distance2(float x, float y, float z) {
227 return x * x + y * y + z * z;
228}
229
230inline float distance(float x, float y, float z) {
231 return sqrtf(distance2(x, y, z));
232}
Jack Palevich106006c2009-08-31 17:42:50 -0700233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234static
235void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
236 jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
237 jfloatArray sphere_ref, jint sphereOffset) {
238 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
239 FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 bool checkOK = positions.check() && sphere.check();
242 if (! checkOK) {
243 return;
244 }
Jack Palevich106006c2009-08-31 17:42:50 -0700245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 positions.bind();
247 sphere.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 if ( positionsCount < 1 ) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700250 doThrowIAE(env, "positionsCount < 1");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 return;
252 }
Jack Palevich106006c2009-08-31 17:42:50 -0700253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 const float* pSrc = positions.mData;
Jack Palevich106006c2009-08-31 17:42:50 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 // find bounding box
257 float x0 = *pSrc++;
258 float x1 = x0;
259 float y0 = *pSrc++;
260 float y1 = y0;
261 float z0 = *pSrc++;
262 float z1 = z0;
Jack Palevich106006c2009-08-31 17:42:50 -0700263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 for(int i = 1; i < positionsCount; i++) {
265 {
266 float x = *pSrc++;
267 if (x < x0) {
268 x0 = x;
269 }
270 else if (x > x1) {
271 x1 = x;
272 }
273 }
274 {
275 float y = *pSrc++;
276 if (y < y0) {
277 y0 = y;
278 }
279 else if (y > y1) {
280 y1 = y;
281 }
282 }
283 {
284 float z = *pSrc++;
285 if (z < z0) {
286 z0 = z;
287 }
288 else if (z > z1) {
289 z1 = z;
290 }
291 }
292 }
Jack Palevich106006c2009-08-31 17:42:50 -0700293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 // Because we know our input meshes fit pretty well into bounding boxes,
295 // just take the diagonal of the box as defining our sphere.
296 float* pSphere = sphere.mData;
297 float dx = x1 - x0;
298 float dy = y1 - y0;
299 float dz = z1 - z0;
300 *pSphere++ = x0 + dx * 0.5f;
301 *pSphere++ = y0 + dy * 0.5f;
302 *pSphere++ = z0 + dz * 0.5f;
303 *pSphere++ = distance(dx, dy, dz) * 0.5f;
Jack Palevich106006c2009-08-31 17:42:50 -0700304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 sphere.commitChanges();
306}
307
308static void normalizePlane(float* p) {
309 float rdist = 1.0f / distance(p[0], p[1], p[2]);
310 for(int i = 0; i < 4; i++) {
311 p[i] *= rdist;
312 }
313}
314
315static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
316 return x0 * x1 + y0 * y1 + z0 * z1;
317}
318
319static inline float signedDistance(const float* pPlane, float x, float y, float z) {
320 return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
321}
322
323// Return true if the sphere intersects or is inside the frustum
324
325static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
326 float x = pSphere[0];
327 float y = pSphere[1];
328 float z = pSphere[2];
329 float negRadius = -pSphere[3];
330 for (int i = 0; i < 6; i++, pFrustum += 4) {
331 if (signedDistance(pFrustum, x, y, z) <= negRadius) {
332 return false;
333 }
334 }
335 return true;
336}
337
338static void computeFrustum(const float* m, float* f) {
339 float m3 = m[3];
340 float m7 = m[7];
341 float m11 = m[11];
342 float m15 = m[15];
343 // right
344 f[0] = m3 - m[0];
345 f[1] = m7 - m[4];
346 f[2] = m11 - m[8];
347 f[3] = m15 - m[12];
348 normalizePlane(f);
349 f+= 4;
350
Jack Palevich106006c2009-08-31 17:42:50 -0700351 // left
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 f[0] = m3 + m[0];
353 f[1] = m7 + m[4];
354 f[2] = m11 + m[8];
355 f[3] = m15 + m[12];
356 normalizePlane(f);
357 f+= 4;
358
359 // top
360 f[0] = m3 - m[1];
361 f[1] = m7 - m[5];
362 f[2] = m11 - m[9];
363 f[3] = m15 - m[13];
364 normalizePlane(f);
365 f+= 4;
366
367 // bottom
368 f[0] = m3 + m[1];
369 f[1] = m7 + m[5];
370 f[2] = m11 + m[9];
371 f[3] = m15 + m[13];
372 normalizePlane(f);
373 f+= 4;
374
375 // far
376 f[0] = m3 - m[2];
377 f[1] = m7 - m[6];
378 f[2] = m11 - m[10];
379 f[3] = m15 - m[14];
380 normalizePlane(f);
381 f+= 4;
382
383 // near
384 f[0] = m3 + m[2];
385 f[1] = m7 + m[6];
386 f[2] = m11 + m[10];
387 f[3] = m15 + m[14];
388 normalizePlane(f);
389}
390
391static
Ashok Bhata0398432014-01-20 20:08:01 +0000392jint util_frustumCullSpheres(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 jfloatArray mvp_ref, jint mvpOffset,
394 jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
395 jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
396 float frustum[6*4];
397 int outputCount;
398 int* pResults;
399 float* pSphere;
400 FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
401 FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
402 IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
Jack Palevich106006c2009-08-31 17:42:50 -0700403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 bool initializedOK = mvp.check() && spheres.check() && results.check();
405 if (! initializedOK) {
406 return -1;
407 }
Jack Palevich106006c2009-08-31 17:42:50 -0700408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 mvp.bind();
410 spheres.bind();
411 results.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 computeFrustum(mvp.mData, frustum);
Jack Palevich106006c2009-08-31 17:42:50 -0700414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 // Cull the spheres
Jack Palevich106006c2009-08-31 17:42:50 -0700416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 pSphere = spheres.mData;
418 pResults = results.mData;
419 outputCount = 0;
420 for(int i = 0; i < spheresCount; i++, pSphere += 4) {
421 if (sphereHitsFrustum(frustum, pSphere)) {
422 if (outputCount < resultsCapacity) {
423 *pResults++ = i;
424 }
425 outputCount++;
426 }
427 }
428 results.commitChanges();
429 return outputCount;
430}
431
432/*
433 public native int visibilityTest(float[] ws, int wsOffset,
434 float[] positions, int positionsOffset,
435 char[] indices, int indicesOffset, int indexCount);
436 */
437
438static
Ashok Bhata0398432014-01-20 20:08:01 +0000439jint util_visibilityTest(JNIEnv *env, jclass clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 jfloatArray ws_ref, jint wsOffset,
441 jfloatArray positions_ref, jint positionsOffset,
442 jcharArray indices_ref, jint indicesOffset, jint indexCount) {
Jack Palevich106006c2009-08-31 17:42:50 -0700443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
445 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
446 UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
Jack Palevich106006c2009-08-31 17:42:50 -0700447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 bool checkOK = ws.check() && positions.check() && indices.check();
449 if (! checkOK) {
450 // Return value will be ignored, because an exception has been thrown.
451 return -1;
452 }
Jack Palevich106006c2009-08-31 17:42:50 -0700453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 if (indices.mLength < indexCount) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700455 doThrowIAE(env, "length < offset + indexCount");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 return -1;
457 }
Jack Palevich106006c2009-08-31 17:42:50 -0700458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 ws.bind();
460 positions.bind();
461 indices.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 return visibilityTest(ws.mData,
464 positions.mData, positions.mLength,
465 indices.mData, indexCount);
466}
467
468#define I(_i, _j) ((_j)+ 4*(_i))
469
470static
471void multiplyMM(float* r, const float* lhs, const float* rhs)
472{
473 for (int i=0 ; i<4 ; i++) {
474 register const float rhs_i0 = rhs[ I(i,0) ];
475 register float ri0 = lhs[ I(0,0) ] * rhs_i0;
476 register float ri1 = lhs[ I(0,1) ] * rhs_i0;
477 register float ri2 = lhs[ I(0,2) ] * rhs_i0;
478 register float ri3 = lhs[ I(0,3) ] * rhs_i0;
479 for (int j=1 ; j<4 ; j++) {
480 register const float rhs_ij = rhs[ I(i,j) ];
481 ri0 += lhs[ I(j,0) ] * rhs_ij;
482 ri1 += lhs[ I(j,1) ] * rhs_ij;
483 ri2 += lhs[ I(j,2) ] * rhs_ij;
484 ri3 += lhs[ I(j,3) ] * rhs_ij;
485 }
486 r[ I(i,0) ] = ri0;
487 r[ I(i,1) ] = ri1;
488 r[ I(i,2) ] = ri2;
489 r[ I(i,3) ] = ri3;
490 }
491}
492
493static
494void util_multiplyMM(JNIEnv *env, jclass clazz,
495 jfloatArray result_ref, jint resultOffset,
496 jfloatArray lhs_ref, jint lhsOffset,
497 jfloatArray rhs_ref, jint rhsOffset) {
498
499 FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
500 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
501 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
Jack Palevich106006c2009-08-31 17:42:50 -0700502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 bool checkOK = resultMat.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 if ( !checkOK ) {
506 return;
507 }
Jack Palevich106006c2009-08-31 17:42:50 -0700508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 resultMat.bind();
510 lhs.bind();
511 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 resultMat.commitChanges();
516}
517
518static
519void multiplyMV(float* r, const float* lhs, const float* rhs)
520{
521 mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
522}
523
524static
525void util_multiplyMV(JNIEnv *env, jclass clazz,
526 jfloatArray result_ref, jint resultOffset,
527 jfloatArray lhs_ref, jint lhsOffset,
528 jfloatArray rhs_ref, jint rhsOffset) {
529
530 FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
531 FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
532 FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
Jack Palevich106006c2009-08-31 17:42:50 -0700533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 bool checkOK = resultV.check() && lhs.check() && rhs.check();
Jack Palevich106006c2009-08-31 17:42:50 -0700535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 if ( !checkOK ) {
537 return;
538 }
Jack Palevich106006c2009-08-31 17:42:50 -0700539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 resultV.bind();
541 lhs.bind();
542 rhs.bind();
Jack Palevich106006c2009-08-31 17:42:50 -0700543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 multiplyMV(resultV.mData, lhs.mData, rhs.mData);
Jack Palevich106006c2009-08-31 17:42:50 -0700545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 resultV.commitChanges();
547}
548
549// ---------------------------------------------------------------------------
550
551static jfieldID nativeBitmapID = 0;
552
553void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
554{
555 jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
Ashok Bhata0398432014-01-20 20:08:01 +0000556 nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557}
558
Siva Velusamy64d10a12012-03-09 14:21:28 -0800559extern void setGLDebugLevel(int level);
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800560void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
Siva Velusamy64d10a12012-03-09 14:21:28 -0800561{
Siva Velusamy0c1761b2012-12-14 17:09:06 -0800562 setGLDebugLevel(level);
Siva Velusamy64d10a12012-03-09 14:21:28 -0800563}
564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565static int checkFormat(SkBitmap::Config config, int format, int type)
566{
567 switch(config) {
568 case SkBitmap::kIndex8_Config:
569 if (format == GL_PALETTE8_RGBA8_OES)
570 return 0;
571 case SkBitmap::kARGB_8888_Config:
572 case SkBitmap::kA8_Config:
573 if (type == GL_UNSIGNED_BYTE)
574 return 0;
575 case SkBitmap::kARGB_4444_Config:
576 case SkBitmap::kRGB_565_Config:
577 switch (type) {
578 case GL_UNSIGNED_SHORT_4_4_4_4:
579 case GL_UNSIGNED_SHORT_5_6_5:
580 case GL_UNSIGNED_SHORT_5_5_5_1:
581 return 0;
582 case GL_UNSIGNED_BYTE:
583 if (format == GL_LUMINANCE_ALPHA)
584 return 0;
585 }
586 break;
587 default:
588 break;
589 }
590 return -1;
591}
592
593static int getInternalFormat(SkBitmap::Config config)
594{
595 switch(config) {
596 case SkBitmap::kA8_Config:
597 return GL_ALPHA;
598 case SkBitmap::kARGB_4444_Config:
599 return GL_RGBA;
600 case SkBitmap::kARGB_8888_Config:
601 return GL_RGBA;
602 case SkBitmap::kIndex8_Config:
603 return GL_PALETTE8_RGBA8_OES;
604 case SkBitmap::kRGB_565_Config:
605 return GL_RGB;
606 default:
607 return -1;
608 }
609}
610
Jack Palevich708c17b2009-03-24 21:05:22 -0700611static int getType(SkBitmap::Config config)
612{
613 switch(config) {
614 case SkBitmap::kA8_Config:
615 return GL_UNSIGNED_BYTE;
616 case SkBitmap::kARGB_4444_Config:
617 return GL_UNSIGNED_SHORT_4_4_4_4;
618 case SkBitmap::kARGB_8888_Config:
619 return GL_UNSIGNED_BYTE;
620 case SkBitmap::kIndex8_Config:
621 return -1; // No type for compressed data.
622 case SkBitmap::kRGB_565_Config:
623 return GL_UNSIGNED_SHORT_5_6_5;
624 default:
625 return -1;
626 }
627}
628
629static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
630 jobject jbitmap)
631{
632 SkBitmap const * nativeBitmap =
Ashok Bhata0398432014-01-20 20:08:01 +0000633 (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
Jack Palevich708c17b2009-03-24 21:05:22 -0700634 const SkBitmap& bitmap(*nativeBitmap);
635 SkBitmap::Config config = bitmap.getConfig();
636 return getInternalFormat(config);
637}
638
639static jint util_getType(JNIEnv *env, jclass clazz,
640 jobject jbitmap)
641{
642 SkBitmap const * nativeBitmap =
Ashok Bhata0398432014-01-20 20:08:01 +0000643 (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
Jack Palevich708c17b2009-03-24 21:05:22 -0700644 const SkBitmap& bitmap(*nativeBitmap);
645 SkBitmap::Config config = bitmap.getConfig();
646 return getType(config);
647}
648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649static jint util_texImage2D(JNIEnv *env, jclass clazz,
650 jint target, jint level, jint internalformat,
651 jobject jbitmap, jint type, jint border)
652{
653 SkBitmap const * nativeBitmap =
Ashok Bhata0398432014-01-20 20:08:01 +0000654 (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 const SkBitmap& bitmap(*nativeBitmap);
656 SkBitmap::Config config = bitmap.getConfig();
657 if (internalformat < 0) {
658 internalformat = getInternalFormat(config);
659 }
Jack Palevich708c17b2009-03-24 21:05:22 -0700660 if (type < 0) {
661 type = getType(config);
662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 int err = checkFormat(config, internalformat, type);
664 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700665 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 bitmap.lockPixels();
667 const int w = bitmap.width();
668 const int h = bitmap.height();
669 const void* p = bitmap.getPixels();
670 if (internalformat == GL_PALETTE8_RGBA8_OES) {
671 if (sizeof(SkPMColor) != sizeof(uint32_t)) {
672 err = -1;
673 goto error;
674 }
675 const size_t size = bitmap.getSize();
676 const size_t palette_size = 256*sizeof(SkPMColor);
Jack Palevich106006c2009-08-31 17:42:50 -0700677 const size_t imageSize = size + palette_size;
678 void* const data = malloc(imageSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 if (data) {
680 void* const pixels = (char*)data + palette_size;
681 SkColorTable* ctable = bitmap.getColorTable();
682 memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
683 memcpy(pixels, p, size);
684 ctable->unlockColors(false);
Jack Palevich106006c2009-08-31 17:42:50 -0700685 glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 free(data);
687 } else {
688 err = -1;
689 }
690 } else {
691 glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
692 }
693error:
694 bitmap.unlockPixels();
695 return err;
696}
697
698static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
699 jint target, jint level, jint xoffset, jint yoffset,
700 jobject jbitmap, jint format, jint type)
701{
702 SkBitmap const * nativeBitmap =
Ashok Bhata0398432014-01-20 20:08:01 +0000703 (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 const SkBitmap& bitmap(*nativeBitmap);
705 SkBitmap::Config config = bitmap.getConfig();
706 if (format < 0) {
707 format = getInternalFormat(config);
708 if (format == GL_PALETTE8_RGBA8_OES)
709 return -1; // glCompressedTexSubImage2D() not supported
710 }
711 int err = checkFormat(config, format, type);
712 if (err)
Jack Palevich106006c2009-08-31 17:42:50 -0700713 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 bitmap.lockPixels();
715 const int w = bitmap.width();
716 const int h = bitmap.height();
717 const void* p = bitmap.getPixels();
718 glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
719 bitmap.unlockPixels();
720 return 0;
721}
722
723/*
Jack Palevicha6276fd2009-12-28 19:31:43 +0800724 * ETC1 methods.
725 */
726
727static jclass nioAccessClass;
728static jclass bufferClass;
729static jmethodID getBasePointerID;
730static jmethodID getBaseArrayID;
731static jmethodID getBaseArrayOffsetID;
732static jfieldID positionID;
733static jfieldID limitID;
734static jfieldID elementSizeShiftID;
735
736/* Cache method IDs each time the class is loaded. */
737
738static void
739nativeClassInitBuffer(JNIEnv *_env)
740{
741 jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
742 nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
743
744 jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
745 bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
746
747 getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
748 "getBasePointer", "(Ljava/nio/Buffer;)J");
749 getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
750 "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
751 getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
752 "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
753 positionID = _env->GetFieldID(bufferClass, "position", "I");
754 limitID = _env->GetFieldID(bufferClass, "limit", "I");
755 elementSizeShiftID =
756 _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
757}
758
759static void *
760getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
761{
762 jint position;
763 jint limit;
764 jint elementSizeShift;
765 jlong pointer;
766 jint offset;
767 void *data;
768
769 position = _env->GetIntField(buffer, positionID);
770 limit = _env->GetIntField(buffer, limitID);
771 elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
772 *remaining = (limit - position) << elementSizeShift;
773 pointer = _env->CallStaticLongMethod(nioAccessClass,
774 getBasePointerID, buffer);
775 if (pointer != 0L) {
Ashok Bhata0398432014-01-20 20:08:01 +0000776 return reinterpret_cast<void *>(pointer);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800777 }
778 return NULL;
779}
780
781class BufferHelper {
782public:
783 BufferHelper(JNIEnv *env, jobject buffer) {
784 mEnv = env;
785 mBuffer = buffer;
786 mData = NULL;
787 mRemaining = 0;
788 }
789
790 bool checkPointer(const char* errorMessage) {
791 if (mBuffer) {
792 mData = getPointer(mEnv, mBuffer, &mRemaining);
793 if (mData == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700794 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800795 }
796 return mData != NULL;
797 } else {
Elliott Hughes8451b252011-04-07 19:17:57 -0700798 doThrowIAE(mEnv, errorMessage);
Jack Palevicha6276fd2009-12-28 19:31:43 +0800799 return false;
800 }
801 }
802
803 inline void* getData() {
804 return mData;
805 }
806
807 inline jint remaining() {
808 return mRemaining;
809 }
810
811private:
812 JNIEnv* mEnv;
813 jobject mBuffer;
814 void* mData;
815 jint mRemaining;
816};
817
818/**
819 * Encode a block of pixels.
820 *
821 * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
822 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
823 * value of pixel (x, y).
824 *
825 * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
826 * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
827 *
828 * @param out an ETC1 compressed version of the data.
829 *
830 */
831static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
832 jobject in, jint validPixelMask, jobject out) {
833 if (validPixelMask < 0 || validPixelMask > 15) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700834 doThrowIAE(env, "validPixelMask");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800835 return;
836 }
837 BufferHelper inB(env, in);
838 BufferHelper outB(env, out);
839 if (inB.checkPointer("in") && outB.checkPointer("out")) {
840 if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700841 doThrowIAE(env, "in's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800842 } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700843 doThrowIAE(env, "out's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800844 } else {
845 etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
846 (etc1_byte*) outB.getData());
847 }
848 }
849}
850
851/**
852 * Decode a block of pixels.
853 *
854 * @param in an ETC1 compressed version of the data.
855 *
856 * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
857 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
858 * value of pixel (x, y).
859 */
860static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
861 jobject in, jobject out){
862 BufferHelper inB(env, in);
863 BufferHelper outB(env, out);
864 if (inB.checkPointer("in") && outB.checkPointer("out")) {
865 if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700866 doThrowIAE(env, "in's remaining data < ENCODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800867 } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700868 doThrowIAE(env, "out's remaining data < DECODED_BLOCK_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800869 } else {
870 etc1_decode_block((etc1_byte*) inB.getData(),
871 (etc1_byte*) outB.getData());
872 }
873 }
874}
875
876/**
877 * Return the size of the encoded image data (does not include size of PKM header).
878 */
879static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
880 jint width, jint height) {
881 return etc1_get_encoded_data_size(width, height);
882}
883
884/**
885 * Encode an entire image.
886 * @param in pointer to the image data. Formatted such that
887 * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
888 * @param out pointer to encoded data. Must be large enough to store entire encoded image.
889 */
890static void etc1_encodeImage(JNIEnv *env, jclass clazz,
891 jobject in, jint width, jint height,
892 jint pixelSize, jint stride, jobject out) {
893 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700894 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800895 return;
896 }
897 BufferHelper inB(env, in);
898 BufferHelper outB(env, out);
899 if (inB.checkPointer("in") && outB.checkPointer("out")) {
900 jint imageSize = stride * height;
901 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
902 if (inB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700903 doThrowIAE(env, "in's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800904 } else if (outB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700905 doThrowIAE(env, "out's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800906 } else {
907 int result = etc1_encode_image((etc1_byte*) inB.getData(),
908 width, height, pixelSize,
909 stride,
910 (etc1_byte*) outB.getData());
911 }
912 }
913}
914
915/**
916 * Decode an entire image.
917 * @param in the encoded data.
918 * @param out pointer to the image data. Will be written such that
919 * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
920 * large enough to store entire image.
921 */
922static void etc1_decodeImage(JNIEnv *env, jclass clazz,
923 jobject in, jobject out,
924 jint width, jint height,
925 jint pixelSize, jint stride) {
926 if (pixelSize < 2 || pixelSize > 3) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700927 doThrowIAE(env, "pixelSize must be 2 or 3");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800928 return;
929 }
930 BufferHelper inB(env, in);
931 BufferHelper outB(env, out);
932 if (inB.checkPointer("in") && outB.checkPointer("out")) {
933 jint imageSize = stride * height;
934 jint encodedImageSize = etc1_get_encoded_data_size(width, height);
935 if (inB.remaining() < encodedImageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700936 doThrowIAE(env, "in's remaining data < encoded image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800937 } else if (outB.remaining() < imageSize) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700938 doThrowIAE(env, "out's remaining data < image size");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800939 } else {
940 int result = etc1_decode_image((etc1_byte*) inB.getData(),
941 (etc1_byte*) outB.getData(),
942 width, height, pixelSize,
943 stride);
944 }
945 }
946}
947
948/**
949 * Format a PKM header
950 */
951static void etc1_formatHeader(JNIEnv *env, jclass clazz,
952 jobject header, jint width, jint height) {
953 BufferHelper headerB(env, header);
954 if (headerB.checkPointer("header") ){
955 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700956 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800957 } else {
958 etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
959 }
960 }
961}
962
963/**
964 * Check if a PKM header is correctly formatted.
965 */
966static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
967 jobject header) {
968 jboolean result = false;
969 BufferHelper headerB(env, header);
970 if (headerB.checkPointer("header") ){
971 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700972 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800973 } else {
974 result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
975 }
976 }
Ashok Bhata0398432014-01-20 20:08:01 +0000977 return result ? JNI_TRUE : JNI_FALSE;
Jack Palevicha6276fd2009-12-28 19:31:43 +0800978}
979
980/**
981 * Read the image width from a PKM header
982 */
983static jint etc1_getWidth(JNIEnv *env, jclass clazz,
984 jobject header) {
985 jint result = 0;
986 BufferHelper headerB(env, header);
987 if (headerB.checkPointer("header") ){
988 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700989 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +0800990 } else {
991 result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
992 }
993 }
994 return result;
995}
996
997/**
998 * Read the image height from a PKM header
999 */
Ashok Bhata0398432014-01-20 20:08:01 +00001000static jint etc1_getHeight(JNIEnv *env, jclass clazz,
Jack Palevicha6276fd2009-12-28 19:31:43 +08001001 jobject header) {
1002 jint result = 0;
1003 BufferHelper headerB(env, header);
1004 if (headerB.checkPointer("header") ){
1005 if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
Elliott Hughes8451b252011-04-07 19:17:57 -07001006 doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
Jack Palevicha6276fd2009-12-28 19:31:43 +08001007 } else {
1008 result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
1009 }
1010 }
1011 return result;
1012}
1013
1014/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 * JNI registration
1016 */
1017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018static JNINativeMethod gMatrixMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001019 { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
1020 { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021};
1022
Elliott Hughes8451b252011-04-07 19:17:57 -07001023static JNINativeMethod gVisibilityMethods[] = {
Jack Palevich106006c2009-08-31 17:42:50 -07001024 { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
Jack Palevich106006c2009-08-31 17:42:50 -07001026 { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027};
1028
1029static JNINativeMethod gUtilsMethods[] = {
1030 {"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
Jack Palevich106006c2009-08-31 17:42:50 -07001031 { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
1032 { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
1033 { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
1034 { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
Siva Velusamy0c1761b2012-12-14 17:09:06 -08001035 { "setTracingLevel", "(I)V", (void*)setTracingLevel },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036};
1037
Jack Palevicha6276fd2009-12-28 19:31:43 +08001038static JNINativeMethod gEtc1Methods[] = {
1039 { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
1040 { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
1041 { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
1042 { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
1043 { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
1044 { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
1045 { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
1046 { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
1047 { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
1048};
1049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050typedef struct _ClassRegistrationInfo {
1051 const char* classPath;
1052 JNINativeMethod* methods;
1053 size_t methodCount;
1054} ClassRegistrationInfo;
1055
1056static ClassRegistrationInfo gClasses[] = {
Elliott Hughes8451b252011-04-07 19:17:57 -07001057 {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
1058 {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
1059 {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
1060 {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061};
1062
1063int register_android_opengl_classes(JNIEnv* env)
1064{
Jack Palevicha6276fd2009-12-28 19:31:43 +08001065 nativeClassInitBuffer(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 int result = 0;
1067 for (int i = 0; i < NELEM(gClasses); i++) {
1068 ClassRegistrationInfo* cri = &gClasses[i];
1069 result = AndroidRuntime::registerNativeMethods(env,
1070 cri->classPath, cri->methods, cri->methodCount);
1071 if (result < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001072 ALOGE("Failed to register %s: %d", cri->classPath, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 break;
1074 }
1075 }
1076 return result;
1077}
1078
1079} // namespace android