util.cpp revision ed79ff0026a44741237a6eb5e3810dbf5d765154
18ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis/**
28ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** Copyright 2007, The Android Open Source Project
38ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis **
48ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** Licensed under the Apache License, Version 2.0 (the "License");
58ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** you may not use this file except in compliance with the License.
68ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** You may obtain a copy of the License at
78ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis **
88ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis **     http://www.apache.org/licenses/LICENSE-2.0
98ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis **
108ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** Unless required by applicable law or agreed to in writing, software
118ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** distributed under the License is distributed on an "AS IS" BASIS,
128ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** See the License for the specific language governing permissions and
148ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis ** limitations under the License.
158ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis */
168ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
178ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include "jni.h"
188ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include "JNIHelp.h"
198ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
208ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <math.h>
21399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall#include <stdio.h>
228ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <stdlib.h>
238ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <string.h>
24399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall#include <assert.h>
258ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <dlfcn.h>
268ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
278ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <GLES/gl.h>
288ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <ETC1/etc1.h>
292adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden
30f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza#include <core/SkBitmap.h>
318ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
328ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include "android_runtime/AndroidRuntime.h"
338ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
348ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#undef LOG_TAG
358ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#define LOG_TAG "OpenGLUtil"
368ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include <utils/Log.h>
378ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#include "utils/misc.h"
389f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
39d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza#include "poly.h"
409f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
418ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisnamespace android {
428ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
43eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopianstatic inline
44fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennisvoid mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
45fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
46399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall    pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
4729a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
489de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
49812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza}
50c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza
51fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballosclass MallocHelper {
527dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stozapublic:
53ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    MallocHelper() {
543559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos        mData = 0;
55ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    }
56127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza
5750101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    ~MallocHelper() {
58eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        if (mData != 0) {
598ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis            free(mData);
608ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        }
612adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    }
628ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
638ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    void* alloc(size_t size) {
642adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        mData = malloc(size);
652adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        return mData;
668ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    }
678ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
688ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisprivate:
693be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    void* mData;
703be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza};
717b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis
728ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis#if 0
732adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFaddenstatic
748ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisvoid
758a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennisprint_poly(const char* label, Poly* pPoly) {
768a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    ALOGI("%s: %d verts", label, pPoly->n);
778a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    for(int i = 0; i < pPoly->n; i++) {
788a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        Poly_vert* pV = & pPoly->vert[i];
798ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        ALOGI("[%d] %g, %g, %g %g", i, pV->sx, pV->sy, pV->sz, pV->sw);
808ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    }
817b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis}
822aff7025482cc40d2ebd45f81cdb318ac1c6f868Lingyun Zhu#endif
832aff7025482cc40d2ebd45f81cdb318ac1c6f868Lingyun Zhu
842aff7025482cc40d2ebd45f81cdb318ac1c6f868Lingyun Zhustatic
852aff7025482cc40d2ebd45f81cdb318ac1c6f868Lingyun Zhuint visibilityTest(float* pWS, float* pPositions, int positionsLength,
862aff7025482cc40d2ebd45f81cdb318ac1c6f868Lingyun Zhu        unsigned short* pIndices, int indexCount) {
878ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    MallocHelper mallocHelper;
888a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    int result = POLY_CLIP_OUT;
897b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis    float* pTransformed = 0;
908ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    int transformedIndexCount = 0;
918ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
92fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    if ( indexCount < 3 ) {
93fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        return POLY_CLIP_OUT;
94fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    }
95fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
96fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    // Find out how many vertices we need to transform
97fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    // We transform every vertex between the min and max indices, inclusive.
98fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    // This is OK for the data sets we expect to use with this function, but
99fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    // for other loads it might be better to use a more sophisticated vertex
100fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    // cache of some sort.
101fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
102fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    int minIndex = 65536;
103fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    int maxIndex = -1;
104fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    for(int i = 0; i < indexCount; i++) {
105fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        int index = pIndices[i];
106fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        if ( index < minIndex ) {
107fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos            minIndex = index;
108fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        }
109fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        if ( index > maxIndex ) {
110fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos            maxIndex = index;
111fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        }
112fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    }
113fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
114fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    if ( maxIndex * 3 > positionsLength) {
115fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        return -1;
116fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    }
117fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
118fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    transformedIndexCount = maxIndex - minIndex + 1;
119fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
120567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos
121567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos    if (pTransformed == 0 ) {
1228ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        return -2;
1232adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    }
1243be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
1253be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    // Transform the vertices
1263be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    {
1273be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        const float* pSrc = pPositions + 3 * minIndex;
1288a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        float* pDst = pTransformed;
1298a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
1308a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis            mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS,  pDst);
1318a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        }
1328ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    }
133ba93b3f8e403636b614a4a379f9421bc70dca84fMathias Agopian
134ba93b3f8e403636b614a4a379f9421bc70dca84fMathias Agopian    // Clip the triangles
1354c00cc11141da7d159eb2323b186ed344115c0f1Jesse Hall
136ba93b3f8e403636b614a4a379f9421bc70dca84fMathias Agopian    Poly poly;
137f78575400977f644cf0b12beb2fa5fc278b6ed4cJesse Hall    float* pDest = & poly.vert[0].sx;
1388a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    for (int i = 0; i < indexCount; i += 3) {
1398ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        poly.n = 3;
1408ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        memcpy(pDest    , pTransformed + 4 * (pIndices[i    ] - minIndex), 4 * sizeof(float));
1418ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
1429f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
1439f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        result = poly_clip_to_frustum(&poly);
1449f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        if ( result != POLY_CLIP_OUT) {
1459f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza            return result;
1469f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        }
1479f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    }
1489f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
1499f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    return result;
1509f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza}
1519f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
1529f3053de78630815d60cf48a2cf2348cc5867c45Dan Stozastatic void doThrowIAE(JNIEnv* env, const char* msg) {
1539f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    jniThrowException(env, "java/lang/IllegalArgumentException", msg);
154d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza}
155d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
156d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stozatemplate<class JArray, class T>
157d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stozaclass ArrayHelper {
158d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stozapublic:
159d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
160d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mEnv = env;
161d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mRef = ref;
162d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mOffset = offset;
163d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mMinSize = minSize;
164d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mBase = 0;
165d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        mReleaseParam = JNI_ABORT;
166d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    }
167d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
168d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    ~ArrayHelper() {
169d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        if (mBase) {
170d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza            mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
171d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        }
172d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    }
173d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
174d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    // We seperate the bounds check from the initialization because we want to
175d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    // be able to bounds-check multiple arrays, and we can't throw an exception
176d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    // after we've called GetPrimitiveArrayCritical.
177d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
178d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    // Return true if the bounds check succeeded
179d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    // Else instruct the runtime to throw an exception
180d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
181d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    bool check() {
182d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        if ( ! mRef) {
183d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza            doThrowIAE(mEnv, "array == null");
184d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza            return false;
1859f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        }
1869f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        if ( mOffset < 0) {
1879f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza            doThrowIAE(mEnv, "offset < 0");
1889f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza            return false;
1899f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        }
1909f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        mLength = mEnv->GetArrayLength(mRef) - mOffset;
1919f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        if (mLength < mMinSize ) {
1929f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza            doThrowIAE(mEnv, "length - offset < n");
1939f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza            return false;
1949f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        }
1959f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza        return true;
1969f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    }
1979f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
198f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian    // Bind the array.
199f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian
2008ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    void bind() {
2012adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
2028ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        mData = mBase + mOffset;
203c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    }
2048a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis
2058a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    void commitChanges() {
2068a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        mReleaseParam = 0;
2078a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    }
208f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian
2098a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    T* mData;
2108ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    int mLength;
2118ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
2128ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisprivate:
213583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballos    T* mBase;
2148ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    JNIEnv* mEnv;
2152adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    JArray mRef;
2168ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    jint mOffset;
2171df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis    jint mMinSize;
218583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballos    int mReleaseParam;
219583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballos};
220583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballos
221583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballostypedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
222583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballostypedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
223583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballostypedef ArrayHelper<jintArray, int> IntArrayHelper;
2248ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennistypedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
2258ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
226eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopianinline float distance2(float x, float y, float z) {
227eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian    return x * x + y * y + z * z;
2282adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden}
229eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian
2308a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennisinline float distance(float x, float y, float z) {
2318a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    return sqrtf(distance2(x, y, z));
2328a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis}
2338a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis
234eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopianstatic
2358a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennisvoid util_computeBoundingSphere(JNIEnv *env, jclass clazz,
236eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian        jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
237eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian        jfloatArray sphere_ref, jint sphereOffset) {
238eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian    FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
239f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza    FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
240365857df8b94c959dea984a63013f6e7730ef976Mathias Agopian
241fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    bool checkOK = positions.check() && sphere.check();
2422adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        if (! checkOK) {
243f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza        return;
244f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza    }
245097ca275f4717a2c47a5d49f302ed2b72c8a1370Marco Nelissen
246f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza    positions.bind();
247f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza    sphere.bind();
248f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza
249fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    if ( positionsCount < 1 ) {
250595264f1af12e25dce57d7c5b1d52ed86ac0d0c9Mathias Agopian        doThrowIAE(env, "positionsCount < 1");
2518a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        return;
2528a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    }
2538a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis
2548a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    const float* pSrc = positions.mData;
25524202f5676c32edeef6544cf36e06b9fc970dbdeMathias Agopian
2568a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    // find bounding box
257fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    float x0 = *pSrc++;
258fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    float x1 = x0;
2598072711307aa98ee5ee6f7369860ae38c3e19656Mathias Agopian    float y0 = *pSrc++;
260fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    float y1 = y0;
261fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis    float z0 = *pSrc++;
2622adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    float z1 = z0;
263fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis
2648a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis    for(int i = 1; i < positionsCount; i++) {
2658a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis        {
2668a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis            float x = *pSrc++;
2678a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis            if (x < x0) {
2688a29ff2a356816694c695db70460f93c7fb4ae6fJamie Gennis                x0 = x;
269fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis            }
270fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis            else if (x > x1) {
271399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall                x1 = x;
272399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            }
273399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall        }
274399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall        {
275399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            float y = *pSrc++;
276399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            if (y < y0) {
277399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall                y0 = y;
278399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            }
279399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            else if (y > y1) {
280399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall                y1 = y;
281399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            }
282399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall        }
283399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall        {
284399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            float z = *pSrc++;
285399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            if (z < z0) {
286399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall                z0 = z;
28729a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza            }
288567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos            else if (z > z1) {
2893be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza                z1 = z;
29029a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza            }
29129a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza        }
2923be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    }
2933be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
29429a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    // Because we know our input meshes fit pretty well into bounding boxes,
2953be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    // just take the diagonal of the box as defining our sphere.
29629a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    float* pSphere = sphere.mData;
29729a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    float dx = x1 - x0;
29829a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    float dy = y1 - y0;
29929a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    float dz = z1 - z0;
30029a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza    *pSphere++ = x0 + dx * 0.5f;
3019de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    *pSphere++ = y0 + dy * 0.5f;
3029de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    *pSphere++ = z0 + dz * 0.5f;
3039de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    *pSphere++ = distance(dx, dy, dz) * 0.5f;
3049de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza
3059de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    sphere.commitChanges();
3069de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza}
3079de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza
3089de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stozastatic void normalizePlane(float* p) {
3099de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    float rdist = 1.0f / distance(p[0], p[1], p[2]);
3109de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    for(int i = 0; i < 4; i++) {
3119de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza        p[i] *= rdist;
3129de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    }
313812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza}
314812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza
315812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stozastatic inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
316812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza    return x0 * x1 + y0 * y1 + z0 * z1;
317812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza}
318812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza
319812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stozastatic inline float signedDistance(const float* pPlane, float x, float y, float z) {
320812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza    return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
321812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza}
322812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza
323812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza// Return true if the sphere intersects or is inside the frustum
324c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza
325c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stozastatic bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
326c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    float x = pSphere[0];
327c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    float y = pSphere[1];
328c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    float z = pSphere[2];
329c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    float negRadius = -pSphere[3];
330c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    for (int i = 0; i < 6; i++, pFrustum += 4) {
331c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza        if (signedDistance(pFrustum, x, y, z) <= negRadius) {
332c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza            return false;
333c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza        }
334c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza    }
3357dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    return true;
3367dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza}
3377dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza
3387dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stozastatic void computeFrustum(const float* m, float* f) {
3397dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    float m3 = m[3];
3407dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    float m7 = m[7];
3417dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    float m11 = m[11];
3427dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    float m15 = m[15];
3437dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    // right
3447dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    f[0] = m3  - m[0];
3457dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    f[1] = m7  - m[4];
3467dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    f[2] = m11 - m[8];
347ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    f[3] = m15 - m[12];
3483559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos    normalizePlane(f);
349ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    f+= 4;
350ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos
351ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    // left
3523559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos    f[0] = m3  + m[0];
3533559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos    f[1] = m7  + m[4];
354ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    f[2] = m11 + m[8];
355ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    f[3] = m15 + m[12];
356ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    normalizePlane(f);
357ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    f+= 4;
358ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos
359ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    // top
360127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f[0] = m3  - m[1];
361ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[1] = m7  - m[5];
362ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[2] = m11 - m[9];
363ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[3] = m15 - m[13];
364ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    normalizePlane(f);
365ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f+= 4;
366ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos
367ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    // bottom
368ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[0] = m3  + m[1];
369ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[1] = m7  + m[5];
370ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[2] = m11 + m[9];
371ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    f[3] = m15 + m[13];
372ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    normalizePlane(f);
373127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f+= 4;
374127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza
375127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    // far
376127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f[0] = m3  - m[2];
377127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f[1] = m7  - m[6];
378127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f[2] = m11 - m[10];
379127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f[3] = m15 - m[14];
380127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    normalizePlane(f);
381127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    f+= 4;
382127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza
383127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    // near
38450101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    f[0] = m3  + m[2];
38550101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    f[1] = m7  + m[6];
3861a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    f[2] = m11 + m[10];
38750101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    f[3] = m15 + m[14];
38850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    normalizePlane(f);
38950101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza}
39050101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza
39150101d02a8eae555887282a5f761fdec57bdaf30Dan Stozastatic
39250101d02a8eae555887282a5f761fdec57bdaf30Dan Stozaint util_frustumCullSpheres(JNIEnv *env, jclass clazz,
39350101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        jfloatArray mvp_ref, jint mvpOffset,
39450101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
39550101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
39650101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    float frustum[6*4];
39750101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    int outputCount;
39850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    int* pResults;
399ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    float* pSphere;
400ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
401ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
402ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
403ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck
4041a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    bool initializedOK = mvp.check() && spheres.check() && results.check();
4051a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck        if (! initializedOK) {
4061a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck        return -1;
407ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    }
40850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza
40950101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    mvp.bind();
41050101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    spheres.bind();
41150101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    results.bind();
41250101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza
41350101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    computeFrustum(mvp.mData, frustum);
41450101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza
41550101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    // Cull the spheres
41650101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza
41750101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    pSphere = spheres.mData;
41850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    pResults = results.mData;
41950101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    outputCount = 0;
42050101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    for(int i = 0; i < spheresCount; i++, pSphere += 4) {
42150101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        if (sphereHitsFrustum(frustum, pSphere)) {
422eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            if (outputCount < resultsCapacity) {
423eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos                *pResults++ = i;
424eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            }
425eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            outputCount++;
426eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        }
427eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    }
428eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    results.commitChanges();
429eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    return outputCount;
430eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos}
431eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos
432eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos/*
433eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos public native int visibilityTest(float[] ws, int wsOffset,
434eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos float[] positions, int positionsOffset,
435eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos char[] indices, int indicesOffset, int indexCount);
436eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos */
437eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos
438eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballosstatic
439eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballosint util_visibilityTest(JNIEnv *env, jclass clazz,
440eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        jfloatArray ws_ref, jint wsOffset,
4418ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        jfloatArray positions_ref, jint positionsOffset,
4428ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        jcharArray indices_ref, jint indicesOffset, jint indexCount) {
4433be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
4443be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
4453be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
4463be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
447466a192d2088f9238d34597d1aa28da41367c1caAndy McFadden
4488ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    bool checkOK = ws.check() && positions.check() && indices.check();
4498ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    if (! checkOK) {
4508ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        // Return value will be ignored, because an exception has been thrown.
4512adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        return -1;
4528ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    }
4538ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
4548ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    if (indices.mLength < indexCount) {
4558ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        doThrowIAE(env, "length < offset + indexCount");
4562adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden        return -1;
4578ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    }
4587b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis
4597b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis    ws.bind();
4608ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    positions.bind();
4618ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    indices.bind();
4628ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
4638ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    return visibilityTest(ws.mData,
4647b305fffc39d0fe0926e7fd2d7f6a524fbce62b7Jamie Gennis            positions.mData, positions.mLength,
4658ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis            indices.mData, indexCount);
4663be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza}
467fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
468fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos#define I(_i, _j) ((_j)+ 4*(_i))
469fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos
470fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballosstatic
471fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballosvoid multiplyMM(float* r, const float* lhs, const float* rhs)
472fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos{
473fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos    for (int i=0 ; i<4 ; i++) {
474fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        register const float rhs_i0 = rhs[ I(i,0) ];
475fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        register float ri0 = lhs[ I(0,0) ] * rhs_i0;
476fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        register float ri1 = lhs[ I(0,1) ] * rhs_i0;
477fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        register float ri2 = lhs[ I(0,2) ] * rhs_i0;
478fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        register float ri3 = lhs[ I(0,3) ] * rhs_i0;
479fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos        for (int j=1 ; j<4 ; j++) {
480fa455354557f6283ff3a7d76979e52fd251c155fPablo Ceballos            register const float rhs_ij = rhs[ I(i,j) ];
4818ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis            ri0 += lhs[ I(j,0) ] * rhs_ij;
4822adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden            ri1 += lhs[ I(j,1) ] * rhs_ij;
4833be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza            ri2 += lhs[ I(j,2) ] * rhs_ij;
4843be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza            ri3 += lhs[ I(j,3) ] * rhs_ij;
4853be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        }
4863be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        r[ I(i,0) ] = ri0;
48712ba0f57d028a9c8f4eb3afddc326b70677d1e0cNaveen Leekha        r[ I(i,1) ] = ri1;
488f78575400977f644cf0b12beb2fa5fc278b6ed4cJesse Hall        r[ I(i,2) ] = ri2;
489567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos        r[ I(i,3) ] = ri3;
490567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos    }
4918ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis}
4921df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis
4931df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennisstatic
494ba93b3f8e403636b614a4a379f9421bc70dca84fMathias Agopianvoid util_multiplyMM(JNIEnv *env, jclass clazz,
495f78575400977f644cf0b12beb2fa5fc278b6ed4cJesse Hall    jfloatArray result_ref, jint resultOffset,
4968ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    jfloatArray lhs_ref, jint lhsOffset,
4979f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    jfloatArray rhs_ref, jint rhsOffset) {
4983be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
4999f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
5009f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
5019f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
5029f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
5039f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    bool checkOK = resultMat.check() && lhs.check() && rhs.check();
5049f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
5053be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza    if ( !checkOK ) {
506d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza        return;
507d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    }
508d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
509d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    resultMat.bind();
510d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    lhs.bind();
511d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    rhs.bind();
512d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
513d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
514d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
515d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    resultMat.commitChanges();
516d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza}
517d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza
518d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stozastatic
519d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stozavoid multiplyMV(float* r, const float* lhs, const float* rhs)
520d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza{
521d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza    mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
522d9822a3843017444364899afc3c23fb5be6b9cb9Dan Stoza}
5233be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
5249f3053de78630815d60cf48a2cf2348cc5867c45Dan Stozastatic
5259f3053de78630815d60cf48a2cf2348cc5867c45Dan Stozavoid util_multiplyMV(JNIEnv *env, jclass clazz,
5269f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    jfloatArray result_ref, jint resultOffset,
5279f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    jfloatArray lhs_ref, jint lhsOffset,
52812ba0f57d028a9c8f4eb3afddc326b70677d1e0cNaveen Leekha    jfloatArray rhs_ref, jint rhsOffset) {
5299f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza
5309f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
5319f3053de78630815d60cf48a2cf2348cc5867c45Dan Stoza    FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
5328ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
5333be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
5348ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    bool checkOK = resultV.check() && lhs.check() && rhs.check();
5352adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden
5368ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    if ( !checkOK ) {
537c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall        return;
538f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian    }
539f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian
540f0bc2f1d8d37977bd3aef3d3326a70e9e69d4246Mathias Agopian    resultV.bind();
541d06421fd37fbb7fd07002e6738fac3a223cb1a62Robert Shih    lhs.bind();
542c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    rhs.bind();
5438ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
5448ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    multiplyMV(resultV.mData, lhs.mData, rhs.mData);
5453be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza
5468ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis    resultV.commitChanges();
5472adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden}
5488ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
5491df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis// ---------------------------------------------------------------------------
5501df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis
551583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballosstatic jfieldID nativeBitmapID = 0;
552583b1b32191992d6ada58b3c61c71932a71c0c4bPablo Ceballos
5538ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisvoid nativeUtilsClassInit(JNIEnv *env, jclass clazz)
5543be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza{
555eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
5562adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
55712ba0f57d028a9c8f4eb3afddc326b70677d1e0cNaveen Leekha}
558eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian
559eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopianextern void setGLDebugLevel(int level);
560eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopianvoid setTracingLevel(JNIEnv *env, jclass clazz, jint level)
561eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian{
562eafabcdc1639fb96062d9e3c39b0ae27b0238ae1Mathias Agopian    setGLDebugLevel(level);
5633be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza}
564fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis
5652adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFaddenstatic int checkFormat(SkBitmap::Config config, int format, int type)
566f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza{
567f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza    switch(config) {
568f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza        case SkBitmap::kIndex8_Config:
569f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza            if (format == GL_PALETTE8_RGBA8_OES)
570fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis                return 0;
571595264f1af12e25dce57d7c5b1d52ed86ac0d0c9Mathias Agopian        case SkBitmap::kARGB_8888_Config:
57224202f5676c32edeef6544cf36e06b9fc970dbdeMathias Agopian        case SkBitmap::kA8_Config:
57324202f5676c32edeef6544cf36e06b9fc970dbdeMathias Agopian            if (type == GL_UNSIGNED_BYTE)
57424202f5676c32edeef6544cf36e06b9fc970dbdeMathias Agopian                return 0;
57593c617fd2a5e7910e0ba5c0ed6da152d30920679Pablo Ceballos        case SkBitmap::kARGB_4444_Config:
576f0eaf25e9247edf4d124bedaeb863f7abdf35a3eDan Stoza        case SkBitmap::kRGB_565_Config:
577fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis            switch (type) {
578fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis                case GL_UNSIGNED_SHORT_4_4_4_4:
5793be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza                case GL_UNSIGNED_SHORT_5_6_5:
580fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis                case GL_UNSIGNED_SHORT_5_5_5_1:
5812adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden                    return 0;
582fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis                case GL_UNSIGNED_BYTE:
5832773004a83624ed41cf3f94f2b11878cd8521812Mathias Agopian                    if (format == GL_LUMINANCE_ALPHA)
584fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis                        return 0;
585fe0a87b54654a1392650e7f1862df473287d8332Jamie Gennis            }
5863be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza            break;
587399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall        default:
588399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall            break;
589399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall    }
590399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall    return -1;
5910ec54e156bed93d59900b742c8e9adcfaee90612Wonsik Kim}
592399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall
593399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hallstatic int getInternalFormat(SkBitmap::Config config)
594399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall{
595399184a4cd728ea1421fb0bc1722274a29e38f4aJesse Hall    switch(config) {
5963be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        case SkBitmap::kA8_Config:
5979de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza            return GL_ALPHA;
59829a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza        case SkBitmap::kARGB_4444_Config:
5993be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza            return GL_RGBA;
6003be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        case SkBitmap::kARGB_8888_Config:
6013be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza            return GL_RGBA;
6023be1c6b60a188dc10025e2ce156c11fac050625dDan Stoza        case SkBitmap::kIndex8_Config:
603567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos            return GL_PALETTE8_RGBA8_OES;
60429a3e90879fd96404c971e7187cd0e05927bbce0Dan Stoza        case SkBitmap::kRGB_565_Config:
6059de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza            return GL_RGB;
6069de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza        default:
6079de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza            return -1;
6089de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza    }
6099de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza}
6109de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza
6119de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stozastatic int getType(SkBitmap::Config config)
6129de7293b0a1b01ebe6fb1ab4a498f144adc8029fDan Stoza{
613812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza    switch(config) {
614812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza        case SkBitmap::kA8_Config:
615812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza            return GL_UNSIGNED_BYTE;
616812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza        case SkBitmap::kARGB_4444_Config:
617812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza            return GL_UNSIGNED_SHORT_4_4_4_4;
618812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza        case SkBitmap::kARGB_8888_Config:
619812ed0644f8f8f71ca403f4e5793f0dbc1fcf9b2Dan Stoza            return GL_UNSIGNED_BYTE;
620c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza        case SkBitmap::kIndex8_Config:
621c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza            return -1; // No type for compressed data.
622c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza        case SkBitmap::kRGB_565_Config:
623c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza            return GL_UNSIGNED_SHORT_5_6_5;
624c6f30bdee1f634eb90d68cb76efe935b6535a1e8Dan Stoza        default:
6257dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza            return -1;
6267dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza    }
6277dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza}
6287dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza
6297dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stozastatic jint util_getInternalFormat(JNIEnv *env, jclass clazz,
6307dde599bf1a0dbef7390d91c2689d506371cdbd7Dan Stoza        jobject jbitmap)
6313559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos{
632ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    SkBitmap const * nativeBitmap =
6333559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos            (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
6343559fbf93801e2c0d9d8fb246fb9b867a361b464Pablo Ceballos    const SkBitmap& bitmap(*nativeBitmap);
635ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    SkBitmap::Config config = bitmap.getConfig();
636ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos    return getInternalFormat(config);
637ccdfd60d79a8b7f1ed6401d0f2e8e29166a10584Pablo Ceballos}
638ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos
639ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballosstatic jint util_getType(JNIEnv *env, jclass clazz,
640ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos        jobject jbitmap)
641ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos{
642ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    SkBitmap const * nativeBitmap =
643ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos            (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
644ff95aabbcc6e8606acbd7933c90eeb9b8b382a21Pablo Ceballos    const SkBitmap& bitmap(*nativeBitmap);
645127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    SkBitmap::Config config = bitmap.getConfig();
646127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza    return getType(config);
647127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza}
648127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza
649127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stozastatic jint util_texImage2D(JNIEnv *env, jclass clazz,
650127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza        jint target, jint level, jint internalformat,
651127fc63e8a15366b4395f1363e8e18eb058d1709Dan Stoza        jobject jbitmap, jint type, jint border)
65250101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza{
65350101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    SkBitmap const * nativeBitmap =
65450101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza            (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
65550101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    const SkBitmap& bitmap(*nativeBitmap);
6561a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    SkBitmap::Config config = bitmap.getConfig();
6571a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    if (internalformat < 0) {
65850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        internalformat = getInternalFormat(config);
65950101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    }
66050101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza    if (type < 0) {
66150101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        type = getType(config);
662ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    }
663ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    int err = checkFormat(config, internalformat, type);
664ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    if (err)
665ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck        return err;
666ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    bitmap.lockPixels();
6671a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    const int w = bitmap.width();
6681a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    const int h = bitmap.height();
6691a61da5e28fa16ad556a58193c8bbeb32a5f636dJohn Reck    const void* p = bitmap.getPixels();
670ce8e5df3c11616f3eb7867ce89558b530651166cJohn Reck    if (internalformat == GL_PALETTE8_RGBA8_OES) {
67150101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        if (sizeof(SkPMColor) != sizeof(uint32_t)) {
67250101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza            err = -1;
67350101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza            goto error;
67450101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        }
67550101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        const size_t size = bitmap.getSize();
67650101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        const size_t palette_size = 256*sizeof(SkPMColor);
67750101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        const size_t imageSize = size + palette_size;
67850101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        void* const data = malloc(imageSize);
67950101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza        if (data) {
68050101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza            void* const pixels = (char*)data + palette_size;
68150101d02a8eae555887282a5f761fdec57bdaf30Dan Stoza            SkColorTable* ctable = bitmap.getColorTable();
682eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
683eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            memcpy(pixels, p, size);
684eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            ctable->unlockColors();
685eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
686eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            free(data);
687eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        } else {
688eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos            err = -1;
689eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        }
690eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    } else {
691eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos        glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
692eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    }
693eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballoserror:
694eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    bitmap.unlockPixels();
695eb7980c224a54f860b7af5ecf30cbc633ae41289Pablo Ceballos    return err;
6968ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis}
6978ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis
6988ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennisstatic jint util_texSubImage2D(JNIEnv *env, jclass clazz,
6998ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        jint target, jint level, jint xoffset, jint yoffset,
7008ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis        jobject jbitmap, jint format, jint type)
7018ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis{
7022adaf04fab35cf47c824d74d901b54094e01ccd3Andy McFadden    SkBitmap const * nativeBitmap =
703c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall            (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
704c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    const SkBitmap& bitmap(*nativeBitmap);
705c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    SkBitmap::Config config = bitmap.getConfig();
706e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    if (format < 0) {
707c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall        format = getInternalFormat(config);
7083c25621ad7d13f64d3ab95a27fa970fbc9998f73Andy McFadden        if (format == GL_PALETTE8_RGBA8_OES)
70982c6bcc9705eabcaf5b9e45bc81867b0e2d61a02Eino-Ville Talvala            return -1; // glCompressedTexSubImage2D() not supported
710c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    }
711c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    int err = checkFormat(config, format, type);
712c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    if (err)
7131681d95989271f3a9ac0dbb93d10e4a29f2b4444Ruben Brunk        return err;
7145065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    bitmap.lockPixels();
7155065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    const int w = bitmap.width();
716c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    const int h = bitmap.height();
717c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    const void* p = bitmap.getPixels();
718e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
7191df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis    bitmap.unlockPixels();
720c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    return 0;
721c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall}
722e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian
723e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian/*
724c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall * ETC1 methods.
725e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian */
726e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian
727e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopianstatic jclass nioAccessClass;
728e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopianstatic jclass bufferClass;
7293c25621ad7d13f64d3ab95a27fa970fbc9998f73Andy McFaddenstatic jmethodID getBasePointerID;
73082c6bcc9705eabcaf5b9e45bc81867b0e2d61a02Eino-Ville Talvalastatic jmethodID getBaseArrayID;
731e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopianstatic jmethodID getBaseArrayOffsetID;
732e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopianstatic jfieldID positionID;
733e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopianstatic jfieldID limitID;
7341681d95989271f3a9ac0dbb93d10e4a29f2b4444Ruben Brunkstatic jfieldID elementSizeShiftID;
7355065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza
7365065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza/* Cache method IDs each time the class is loaded. */
7375065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza
7385065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stozastatic void
7395065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan StozanativeClassInitBuffer(JNIEnv *_env)
740c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall{
741c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
742e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
743e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian
744c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
745e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
746e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian
7473c25621ad7d13f64d3ab95a27fa970fbc9998f73Andy McFadden    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
74882c6bcc9705eabcaf5b9e45bc81867b0e2d61a02Eino-Ville Talvala            "getBasePointer", "(Ljava/nio/Buffer;)J");
749e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
750e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
751e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
752567dbbb6dd42be5013fcde0dadb3316d85f2fa0dPablo Ceballos            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
753e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    positionID = _env->GetFieldID(bufferClass, "position", "I");
754e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    limitID = _env->GetFieldID(bufferClass, "limit", "I");
755e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    elementSizeShiftID =
756e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
757e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian}
758e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian
7593c25621ad7d13f64d3ab95a27fa970fbc9998f73Andy McFaddenstatic void *
76082c6bcc9705eabcaf5b9e45bc81867b0e2d61a02Eino-Ville TalvalagetPointer(JNIEnv *_env, jobject buffer, jint *remaining)
761e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian{
762e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    jint position;
763e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    jint limit;
7641681d95989271f3a9ac0dbb93d10e4a29f2b4444Ruben Brunk    jint elementSizeShift;
765e142428a9c8b9d2380032cd4d7b55ee440fe8770Mathias Agopian    jlong pointer;
7661df8c345854155cbbcb9f80de9d12d66ea70ac08Jamie Gennis    jint offset;
7675065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    void *data;
7685065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza
7695065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    position = _env->GetIntField(buffer, positionID);
7705065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    limit = _env->GetIntField(buffer, limitID);
7715065a55291b67f584d7b0be3fa3cfc4e29a3cd1cDan Stoza    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
772c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    *remaining = (limit - position) << elementSizeShift;
773c777b0b3b9b0ea5d8e378fccde6935765e28e329Jesse Hall    pointer = _env->CallStaticLongMethod(nioAccessClass,
7748ba32fade11abb73f3fd47ea0953c9528eb5b91fJamie Gennis            getBasePointerID, buffer);
775    if (pointer != 0L) {
776        return (void *) (jint) pointer;
777    }
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) {
794                doThrowIAE(mEnv, errorMessage);
795            }
796            return mData != NULL;
797        } else {
798            doThrowIAE(mEnv, errorMessage);
799            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) {
834        doThrowIAE(env, "validPixelMask");
835        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) {
841            doThrowIAE(env, "in's remaining data < DECODED_BLOCK_SIZE");
842        } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
843            doThrowIAE(env, "out's remaining data < ENCODED_BLOCK_SIZE");
844        } 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) {
866            doThrowIAE(env, "in's remaining data < ENCODED_BLOCK_SIZE");
867        } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
868            doThrowIAE(env, "out's remaining data < DECODED_BLOCK_SIZE");
869        } 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) {
894        doThrowIAE(env, "pixelSize must be 2 or 3");
895        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) {
903            doThrowIAE(env, "in's remaining data < image size");
904        } else if (outB.remaining() < encodedImageSize) {
905            doThrowIAE(env, "out's remaining data < encoded image size");
906        } 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) {
927        doThrowIAE(env, "pixelSize must be 2 or 3");
928        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) {
936            doThrowIAE(env, "in's remaining data < encoded image size");
937        } else if (outB.remaining() < imageSize) {
938            doThrowIAE(env, "out's remaining data < image size");
939        } 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) {
956            doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
957        } 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) {
972            doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
973        } else {
974            result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
975        }
976    }
977    return result;
978}
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) {
989            doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
990        } 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 */
1000static int etc1_getHeight(JNIEnv *env, jclass clazz,
1001        jobject header) {
1002    jint result = 0;
1003    BufferHelper headerB(env, header);
1004    if (headerB.checkPointer("header") ){
1005        if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
1006            doThrowIAE(env, "header's remaining data < ETC_PKM_HEADER_SIZE");
1007        } else {
1008            result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
1009        }
1010    }
1011    return result;
1012}
1013
1014/*
1015 * JNI registration
1016 */
1017
1018static JNINativeMethod gMatrixMethods[] = {
1019    { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
1020    { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
1021};
1022
1023static JNINativeMethod gVisibilityMethods[] = {
1024    { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
1025    { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
1026    { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
1027};
1028
1029static JNINativeMethod gUtilsMethods[] = {
1030    {"nativeClassInit", "()V",                          (void*)nativeUtilsClassInit },
1031    { "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 },
1035    { "setTracingLevel", "(I)V",                        (void*)setTracingLevel },
1036};
1037
1038static 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
1050typedef struct _ClassRegistrationInfo {
1051    const char* classPath;
1052    JNINativeMethod* methods;
1053    size_t methodCount;
1054} ClassRegistrationInfo;
1055
1056static ClassRegistrationInfo gClasses[] = {
1057    {"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)},
1061};
1062
1063int register_android_opengl_classes(JNIEnv* env)
1064{
1065    nativeClassInitBuffer(env);
1066    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) {
1072            ALOGE("Failed to register %s: %d", cri->classPath, result);
1073            break;
1074        }
1075    }
1076    return result;
1077}
1078
1079} // namespace android
1080