1 /**
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <nativehelper/jni.h>
18 #include <math.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <dlfcn.h>
24
25 #include <GLES/gl.h>
26
27 #include <core/SkBitmap.h>
28
29 #include "android_runtime/AndroidRuntime.h"
30
31 #undef LOG_TAG
32 #define LOG_TAG "OpenGLUtil"
33 #include <utils/Log.h>
34 #include "utils/misc.h"
35
36 #include "poly.h"
37
38 namespace android {
39
40 static jclass gIAEClass;
41 static jclass gUOEClass;
42
43 static inline
mx4transform(float x,float y,float z,float w,const float * pM,float * pDest)44 void 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
51 class MallocHelper {
52 public:
MallocHelper()53 MallocHelper() {
54 mData = 0;
55 }
56
~MallocHelper()57 ~MallocHelper() {
58 if (mData != 0) {
59 free(mData);
60 }
61 }
62
alloc(size_t size)63 void* alloc(size_t size) {
64 mData = malloc(size);
65 return mData;
66 }
67
68 private:
69 void* mData;
70 };
71
72 #if 0
73 static
74 void
75 print_poly(const char* label, Poly* pPoly) {
76 LOGI("%s: %d verts", label, pPoly->n);
77 for(int i = 0; i < pPoly->n; i++) {
78 Poly_vert* pV = & pPoly->vert[i];
79 LOGI("[%d] %g, %g, %g %g", i, pV->sx, pV->sy, pV->sz, pV->sw);
80 }
81 }
82 #endif
83
84 static
visibilityTest(float * pWS,float * pPositions,int positionsLength,unsigned short * pIndices,int indexCount)85 int 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;
91
92 if ( indexCount < 3 ) {
93 return POLY_CLIP_OUT;
94 }
95
96 // 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.
101
102 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 }
113
114 if ( maxIndex * 3 > positionsLength) {
115 return -1;
116 }
117
118 transformedIndexCount = maxIndex - minIndex + 1;
119 pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
120
121 if (pTransformed == 0 ) {
122 return -2;
123 }
124
125 // 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 }
133
134 // Clip the triangles
135
136 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
152 template<class JArray, class T>
153 class ArrayHelper {
154 public:
ArrayHelper(JNIEnv * env,JArray ref,jint offset,jint minSize)155 ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
156 mEnv = env;
157 mRef = ref;
158 mOffset = offset;
159 mMinSize = minSize;
160 mBase = 0;
161 mReleaseParam = JNI_ABORT;
162 }
163
~ArrayHelper()164 ~ArrayHelper() {
165 if (mBase) {
166 mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
167 }
168 }
169
170 // We seperate the bounds check from the initialization because we want to
171 // be able to bounds-check multiple arrays, and we can't throw an exception
172 // after we've called GetPrimitiveArrayCritical.
173
174 // Return true if the bounds check succeeded
175 // Else instruct the runtime to throw an exception
176
check()177 bool check() {
178 if ( ! mRef) {
179 mEnv->ThrowNew(gIAEClass, "array == null");
180 return false;
181 }
182 if ( mOffset < 0) {
183 mEnv->ThrowNew(gIAEClass, "offset < 0");
184 return false;
185 }
186 mLength = mEnv->GetArrayLength(mRef) - mOffset;
187 if (mLength < mMinSize ) {
188 mEnv->ThrowNew(gIAEClass, "length - offset < n");
189 return false;
190 }
191 return true;
192 }
193
194 // Bind the array.
195
bind()196 void bind() {
197 mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
198 mData = mBase + mOffset;
199 }
200
commitChanges()201 void commitChanges() {
202 mReleaseParam = 0;
203 }
204
205 T* mData;
206 int mLength;
207
208 private:
209 T* mBase;
210 JNIEnv* mEnv;
211 JArray mRef;
212 jint mOffset;
213 jint mMinSize;
214 int mReleaseParam;
215 };
216
217 typedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
218 typedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
219 typedef ArrayHelper<jintArray, int> IntArrayHelper;
220 typedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
221
distance2(float x,float y,float z)222 inline float distance2(float x, float y, float z) {
223 return x * x + y * y + z * z;
224 }
225
distance(float x,float y,float z)226 inline float distance(float x, float y, float z) {
227 return sqrtf(distance2(x, y, z));
228 }
229
230 static
util_computeBoundingSphere(JNIEnv * env,jclass clazz,jfloatArray positions_ref,jint positionsOffset,jint positionsCount,jfloatArray sphere_ref,jint sphereOffset)231 void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
232 jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
233 jfloatArray sphere_ref, jint sphereOffset) {
234 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
235 FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
236
237 bool checkOK = positions.check() && sphere.check();
238 if (! checkOK) {
239 return;
240 }
241
242 positions.bind();
243 sphere.bind();
244
245 if ( positionsCount < 1 ) {
246 env->ThrowNew(gIAEClass, "positionsCount < 1");
247 return;
248 }
249
250 const float* pSrc = positions.mData;
251
252 // find bounding box
253 float x0 = *pSrc++;
254 float x1 = x0;
255 float y0 = *pSrc++;
256 float y1 = y0;
257 float z0 = *pSrc++;
258 float z1 = z0;
259
260 for(int i = 1; i < positionsCount; i++) {
261 {
262 float x = *pSrc++;
263 if (x < x0) {
264 x0 = x;
265 }
266 else if (x > x1) {
267 x1 = x;
268 }
269 }
270 {
271 float y = *pSrc++;
272 if (y < y0) {
273 y0 = y;
274 }
275 else if (y > y1) {
276 y1 = y;
277 }
278 }
279 {
280 float z = *pSrc++;
281 if (z < z0) {
282 z0 = z;
283 }
284 else if (z > z1) {
285 z1 = z;
286 }
287 }
288 }
289
290 // Because we know our input meshes fit pretty well into bounding boxes,
291 // just take the diagonal of the box as defining our sphere.
292 float* pSphere = sphere.mData;
293 float dx = x1 - x0;
294 float dy = y1 - y0;
295 float dz = z1 - z0;
296 *pSphere++ = x0 + dx * 0.5f;
297 *pSphere++ = y0 + dy * 0.5f;
298 *pSphere++ = z0 + dz * 0.5f;
299 *pSphere++ = distance(dx, dy, dz) * 0.5f;
300
301 sphere.commitChanges();
302 }
303
normalizePlane(float * p)304 static void normalizePlane(float* p) {
305 float rdist = 1.0f / distance(p[0], p[1], p[2]);
306 for(int i = 0; i < 4; i++) {
307 p[i] *= rdist;
308 }
309 }
310
dot3(float x0,float y0,float z0,float x1,float y1,float z1)311 static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
312 return x0 * x1 + y0 * y1 + z0 * z1;
313 }
314
signedDistance(const float * pPlane,float x,float y,float z)315 static inline float signedDistance(const float* pPlane, float x, float y, float z) {
316 return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
317 }
318
319 // Return true if the sphere intersects or is inside the frustum
320
sphereHitsFrustum(const float * pFrustum,const float * pSphere)321 static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
322 float x = pSphere[0];
323 float y = pSphere[1];
324 float z = pSphere[2];
325 float negRadius = -pSphere[3];
326 for (int i = 0; i < 6; i++, pFrustum += 4) {
327 if (signedDistance(pFrustum, x, y, z) <= negRadius) {
328 return false;
329 }
330 }
331 return true;
332 }
333
computeFrustum(const float * m,float * f)334 static void computeFrustum(const float* m, float* f) {
335 float m3 = m[3];
336 float m7 = m[7];
337 float m11 = m[11];
338 float m15 = m[15];
339 // right
340 f[0] = m3 - m[0];
341 f[1] = m7 - m[4];
342 f[2] = m11 - m[8];
343 f[3] = m15 - m[12];
344 normalizePlane(f);
345 f+= 4;
346
347 // left
348 f[0] = m3 + m[0];
349 f[1] = m7 + m[4];
350 f[2] = m11 + m[8];
351 f[3] = m15 + m[12];
352 normalizePlane(f);
353 f+= 4;
354
355 // top
356 f[0] = m3 - m[1];
357 f[1] = m7 - m[5];
358 f[2] = m11 - m[9];
359 f[3] = m15 - m[13];
360 normalizePlane(f);
361 f+= 4;
362
363 // bottom
364 f[0] = m3 + m[1];
365 f[1] = m7 + m[5];
366 f[2] = m11 + m[9];
367 f[3] = m15 + m[13];
368 normalizePlane(f);
369 f+= 4;
370
371 // far
372 f[0] = m3 - m[2];
373 f[1] = m7 - m[6];
374 f[2] = m11 - m[10];
375 f[3] = m15 - m[14];
376 normalizePlane(f);
377 f+= 4;
378
379 // near
380 f[0] = m3 + m[2];
381 f[1] = m7 + m[6];
382 f[2] = m11 + m[10];
383 f[3] = m15 + m[14];
384 normalizePlane(f);
385 }
386
387 static
util_frustumCullSpheres(JNIEnv * env,jclass clazz,jfloatArray mvp_ref,jint mvpOffset,jfloatArray spheres_ref,jint spheresOffset,jint spheresCount,jintArray results_ref,jint resultsOffset,jint resultsCapacity)388 int util_frustumCullSpheres(JNIEnv *env, jclass clazz,
389 jfloatArray mvp_ref, jint mvpOffset,
390 jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
391 jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
392 float frustum[6*4];
393 int outputCount;
394 int* pResults;
395 float* pSphere;
396 FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
397 FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
398 IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
399
400 bool initializedOK = mvp.check() && spheres.check() && results.check();
401 if (! initializedOK) {
402 return -1;
403 }
404
405 mvp.bind();
406 spheres.bind();
407 results.bind();
408
409 computeFrustum(mvp.mData, frustum);
410
411 // Cull the spheres
412
413 pSphere = spheres.mData;
414 pResults = results.mData;
415 outputCount = 0;
416 for(int i = 0; i < spheresCount; i++, pSphere += 4) {
417 if (sphereHitsFrustum(frustum, pSphere)) {
418 if (outputCount < resultsCapacity) {
419 *pResults++ = i;
420 }
421 outputCount++;
422 }
423 }
424 results.commitChanges();
425 return outputCount;
426 }
427
428 /*
429 public native int visibilityTest(float[] ws, int wsOffset,
430 float[] positions, int positionsOffset,
431 char[] indices, int indicesOffset, int indexCount);
432 */
433
434 static
util_visibilityTest(JNIEnv * env,jclass clazz,jfloatArray ws_ref,jint wsOffset,jfloatArray positions_ref,jint positionsOffset,jcharArray indices_ref,jint indicesOffset,jint indexCount)435 int util_visibilityTest(JNIEnv *env, jclass clazz,
436 jfloatArray ws_ref, jint wsOffset,
437 jfloatArray positions_ref, jint positionsOffset,
438 jcharArray indices_ref, jint indicesOffset, jint indexCount) {
439
440 FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
441 FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
442 UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
443
444 bool checkOK = ws.check() && positions.check() && indices.check();
445 if (! checkOK) {
446 // Return value will be ignored, because an exception has been thrown.
447 return -1;
448 }
449
450 if (indices.mLength < indexCount) {
451 env->ThrowNew(gIAEClass, "length < offset + indexCount");
452 // Return value will be ignored, because an exception has been thrown.
453 return -1;
454 }
455
456 ws.bind();
457 positions.bind();
458 indices.bind();
459
460 return visibilityTest(ws.mData,
461 positions.mData, positions.mLength,
462 indices.mData, indexCount);
463 }
464
465 #define I(_i, _j) ((_j)+ 4*(_i))
466
467 static
multiplyMM(float * r,const float * lhs,const float * rhs)468 void multiplyMM(float* r, const float* lhs, const float* rhs)
469 {
470 for (int i=0 ; i<4 ; i++) {
471 register const float rhs_i0 = rhs[ I(i,0) ];
472 register float ri0 = lhs[ I(0,0) ] * rhs_i0;
473 register float ri1 = lhs[ I(0,1) ] * rhs_i0;
474 register float ri2 = lhs[ I(0,2) ] * rhs_i0;
475 register float ri3 = lhs[ I(0,3) ] * rhs_i0;
476 for (int j=1 ; j<4 ; j++) {
477 register const float rhs_ij = rhs[ I(i,j) ];
478 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
490 static
util_multiplyMM(JNIEnv * env,jclass clazz,jfloatArray result_ref,jint resultOffset,jfloatArray lhs_ref,jint lhsOffset,jfloatArray rhs_ref,jint rhsOffset)491 void 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);
499
500 bool checkOK = resultMat.check() && lhs.check() && rhs.check();
501
502 if ( !checkOK ) {
503 return;
504 }
505
506 resultMat.bind();
507 lhs.bind();
508 rhs.bind();
509
510 multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
511
512 resultMat.commitChanges();
513 }
514
515 static
multiplyMV(float * r,const float * lhs,const float * rhs)516 void multiplyMV(float* r, const float* lhs, const float* rhs)
517 {
518 mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
519 }
520
521 static
util_multiplyMV(JNIEnv * env,jclass clazz,jfloatArray result_ref,jint resultOffset,jfloatArray lhs_ref,jint lhsOffset,jfloatArray rhs_ref,jint rhsOffset)522 void 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);
530
531 bool checkOK = resultV.check() && lhs.check() && rhs.check();
532
533 if ( !checkOK ) {
534 return;
535 }
536
537 resultV.bind();
538 lhs.bind();
539 rhs.bind();
540
541 multiplyMV(resultV.mData, lhs.mData, rhs.mData);
542
543 resultV.commitChanges();
544 }
545
546 // ---------------------------------------------------------------------------
547
548 static jfieldID nativeBitmapID = 0;
549
nativeUtilsClassInit(JNIEnv * env,jclass clazz)550 void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
551 {
552 jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
553 nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
554 }
555
checkFormat(SkBitmap::Config config,int format,int type)556 static int checkFormat(SkBitmap::Config config, int format, int type)
557 {
558 switch(config) {
559 case SkBitmap::kIndex8_Config:
560 if (format == GL_PALETTE8_RGBA8_OES)
561 return 0;
562 case SkBitmap::kARGB_8888_Config:
563 case SkBitmap::kA8_Config:
564 if (type == GL_UNSIGNED_BYTE)
565 return 0;
566 case SkBitmap::kARGB_4444_Config:
567 case SkBitmap::kRGB_565_Config:
568 switch (type) {
569 case GL_UNSIGNED_SHORT_4_4_4_4:
570 case GL_UNSIGNED_SHORT_5_6_5:
571 case GL_UNSIGNED_SHORT_5_5_5_1:
572 return 0;
573 case GL_UNSIGNED_BYTE:
574 if (format == GL_LUMINANCE_ALPHA)
575 return 0;
576 }
577 break;
578 default:
579 break;
580 }
581 return -1;
582 }
583
getInternalFormat(SkBitmap::Config config)584 static int getInternalFormat(SkBitmap::Config config)
585 {
586 switch(config) {
587 case SkBitmap::kA8_Config:
588 return GL_ALPHA;
589 case SkBitmap::kARGB_4444_Config:
590 return GL_RGBA;
591 case SkBitmap::kARGB_8888_Config:
592 return GL_RGBA;
593 case SkBitmap::kIndex8_Config:
594 return GL_PALETTE8_RGBA8_OES;
595 case SkBitmap::kRGB_565_Config:
596 return GL_RGB;
597 default:
598 return -1;
599 }
600 }
601
getType(SkBitmap::Config config)602 static int getType(SkBitmap::Config config)
603 {
604 switch(config) {
605 case SkBitmap::kA8_Config:
606 return GL_UNSIGNED_BYTE;
607 case SkBitmap::kARGB_4444_Config:
608 return GL_UNSIGNED_SHORT_4_4_4_4;
609 case SkBitmap::kARGB_8888_Config:
610 return GL_UNSIGNED_BYTE;
611 case SkBitmap::kIndex8_Config:
612 return -1; // No type for compressed data.
613 case SkBitmap::kRGB_565_Config:
614 return GL_UNSIGNED_SHORT_5_6_5;
615 default:
616 return -1;
617 }
618 }
619
util_getInternalFormat(JNIEnv * env,jclass clazz,jobject jbitmap)620 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
621 jobject jbitmap)
622 {
623 SkBitmap const * nativeBitmap =
624 (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
625 const SkBitmap& bitmap(*nativeBitmap);
626 SkBitmap::Config config = bitmap.getConfig();
627 return getInternalFormat(config);
628 }
629
util_getType(JNIEnv * env,jclass clazz,jobject jbitmap)630 static jint util_getType(JNIEnv *env, jclass clazz,
631 jobject jbitmap)
632 {
633 SkBitmap const * nativeBitmap =
634 (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
635 const SkBitmap& bitmap(*nativeBitmap);
636 SkBitmap::Config config = bitmap.getConfig();
637 return getType(config);
638 }
639
util_texImage2D(JNIEnv * env,jclass clazz,jint target,jint level,jint internalformat,jobject jbitmap,jint type,jint border)640 static jint util_texImage2D(JNIEnv *env, jclass clazz,
641 jint target, jint level, jint internalformat,
642 jobject jbitmap, jint type, jint border)
643 {
644 SkBitmap const * nativeBitmap =
645 (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
646 const SkBitmap& bitmap(*nativeBitmap);
647 SkBitmap::Config config = bitmap.getConfig();
648 if (internalformat < 0) {
649 internalformat = getInternalFormat(config);
650 }
651 if (type < 0) {
652 type = getType(config);
653 }
654 int err = checkFormat(config, internalformat, type);
655 if (err)
656 return err;
657 bitmap.lockPixels();
658 const int w = bitmap.width();
659 const int h = bitmap.height();
660 const void* p = bitmap.getPixels();
661 if (internalformat == GL_PALETTE8_RGBA8_OES) {
662 if (sizeof(SkPMColor) != sizeof(uint32_t)) {
663 err = -1;
664 goto error;
665 }
666 const size_t size = bitmap.getSize();
667 const size_t palette_size = 256*sizeof(SkPMColor);
668 const size_t imageSize = size + palette_size;
669 void* const data = malloc(imageSize);
670 if (data) {
671 void* const pixels = (char*)data + palette_size;
672 SkColorTable* ctable = bitmap.getColorTable();
673 memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
674 memcpy(pixels, p, size);
675 ctable->unlockColors(false);
676 glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
677 free(data);
678 } else {
679 err = -1;
680 }
681 } else {
682 glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
683 }
684 error:
685 bitmap.unlockPixels();
686 return err;
687 }
688
util_texSubImage2D(JNIEnv * env,jclass clazz,jint target,jint level,jint xoffset,jint yoffset,jobject jbitmap,jint format,jint type)689 static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
690 jint target, jint level, jint xoffset, jint yoffset,
691 jobject jbitmap, jint format, jint type)
692 {
693 SkBitmap const * nativeBitmap =
694 (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
695 const SkBitmap& bitmap(*nativeBitmap);
696 SkBitmap::Config config = bitmap.getConfig();
697 if (format < 0) {
698 format = getInternalFormat(config);
699 if (format == GL_PALETTE8_RGBA8_OES)
700 return -1; // glCompressedTexSubImage2D() not supported
701 }
702 int err = checkFormat(config, format, type);
703 if (err)
704 return err;
705 bitmap.lockPixels();
706 const int w = bitmap.width();
707 const int h = bitmap.height();
708 const void* p = bitmap.getPixels();
709 glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
710 bitmap.unlockPixels();
711 return 0;
712 }
713
714 /*
715 * JNI registration
716 */
717
718 static void
lookupClasses(JNIEnv * env)719 lookupClasses(JNIEnv* env) {
720 gIAEClass = (jclass) env->NewGlobalRef(
721 env->FindClass("java/lang/IllegalArgumentException"));
722 gUOEClass = (jclass) env->NewGlobalRef(
723 env->FindClass("java/lang/UnsupportedOperationException"));
724 }
725
726 static JNINativeMethod gMatrixMethods[] = {
727 { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
728 { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
729 };
730
731 static JNINativeMethod gVisiblityMethods[] = {
732 { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
733 { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
734 { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
735 };
736
737 static JNINativeMethod gUtilsMethods[] = {
738 {"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
739 { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
740 { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
741 { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
742 { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
743 };
744
745 typedef struct _ClassRegistrationInfo {
746 const char* classPath;
747 JNINativeMethod* methods;
748 size_t methodCount;
749 } ClassRegistrationInfo;
750
751 static ClassRegistrationInfo gClasses[] = {
752 {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
753 {"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)},
754 {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
755 };
756
register_android_opengl_classes(JNIEnv * env)757 int register_android_opengl_classes(JNIEnv* env)
758 {
759 lookupClasses(env);
760 int result = 0;
761 for (int i = 0; i < NELEM(gClasses); i++) {
762 ClassRegistrationInfo* cri = &gClasses[i];
763 result = AndroidRuntime::registerNativeMethods(env,
764 cri->classPath, cri->methods, cri->methodCount);
765 if (result < 0) {
766 LOGE("Failed to register %s: %d", cri->classPath, result);
767 break;
768 }
769 }
770 return result;
771 }
772
773 } // namespace android
774
775