1/*
2 * Copyright (C) 2010 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
17package com.android.gallery3d.ui;
18
19import java.nio.Buffer;
20import java.nio.ByteBuffer;
21import java.nio.ByteOrder;
22import java.nio.CharBuffer;
23import java.nio.DoubleBuffer;
24import java.nio.FloatBuffer;
25import java.nio.IntBuffer;
26import java.nio.LongBuffer;
27import java.nio.ShortBuffer;
28
29import javax.microedition.khronos.opengles.GL10;
30
31public class PointerInfo {
32
33    /**
34     * The number of coordinates per vertex. 1..4
35     */
36    public int mSize;
37
38    /**
39     * The type of each coordinate.
40     */
41    public int mType;
42
43    /**
44     * The byte offset between consecutive vertices. 0 means mSize *
45     * sizeof(mType)
46     */
47    public int mStride;
48    public Buffer mPointer;
49    public ByteBuffer mTempByteBuffer;
50
51    public PointerInfo(int size, int type, int stride, Buffer pointer) {
52        mSize = size;
53        mType = type;
54        mStride = stride;
55        mPointer = pointer;
56    }
57
58    private int getStride() {
59        return mStride > 0 ? mStride : sizeof(mType) * mSize;
60    }
61
62    public void bindByteBuffer() {
63        mTempByteBuffer = mPointer == null ? null : toByteBuffer(-1, mPointer);
64    }
65
66    public void unbindByteBuffer() {
67        mTempByteBuffer = null;
68    }
69
70    private static int sizeof(int type) {
71        switch (type) {
72        case GL10.GL_UNSIGNED_BYTE:
73            return 1;
74        case GL10.GL_BYTE:
75            return 1;
76        case GL10.GL_SHORT:
77            return 2;
78        case GL10.GL_FIXED:
79            return 4;
80        case GL10.GL_FLOAT:
81            return 4;
82        default:
83            return 0;
84        }
85    }
86
87    private static ByteBuffer toByteBuffer(int byteCount, Buffer input) {
88        ByteBuffer result = null;
89        boolean convertWholeBuffer = (byteCount < 0);
90        if (input instanceof ByteBuffer) {
91            ByteBuffer input2 = (ByteBuffer) input;
92            int position = input2.position();
93            if (convertWholeBuffer) {
94                byteCount = input2.limit() - position;
95            }
96            result = ByteBuffer.allocate(byteCount).order(input2.order());
97            for (int i = 0; i < byteCount; i++) {
98                result.put(input2.get());
99            }
100            input2.position(position);
101        } else if (input instanceof CharBuffer) {
102            CharBuffer input2 = (CharBuffer) input;
103            int position = input2.position();
104            if (convertWholeBuffer) {
105                byteCount = (input2.limit() - position) * 2;
106            }
107            result = ByteBuffer.allocate(byteCount).order(input2.order());
108            CharBuffer result2 = result.asCharBuffer();
109            for (int i = 0; i < byteCount / 2; i++) {
110                result2.put(input2.get());
111            }
112            input2.position(position);
113        } else if (input instanceof ShortBuffer) {
114            ShortBuffer input2 = (ShortBuffer) input;
115            int position = input2.position();
116            if (convertWholeBuffer) {
117                byteCount = (input2.limit() - position)* 2;
118            }
119            result = ByteBuffer.allocate(byteCount).order(input2.order());
120            ShortBuffer result2 = result.asShortBuffer();
121            for (int i = 0; i < byteCount / 2; i++) {
122                result2.put(input2.get());
123            }
124            input2.position(position);
125        } else if (input instanceof IntBuffer) {
126            IntBuffer input2 = (IntBuffer) input;
127            int position = input2.position();
128            if (convertWholeBuffer) {
129                byteCount = (input2.limit() - position) * 4;
130            }
131            result = ByteBuffer.allocate(byteCount).order(input2.order());
132            IntBuffer result2 = result.asIntBuffer();
133            for (int i = 0; i < byteCount / 4; i++) {
134                result2.put(input2.get());
135            }
136            input2.position(position);
137        } else if (input instanceof FloatBuffer) {
138            FloatBuffer input2 = (FloatBuffer) input;
139            int position = input2.position();
140            if (convertWholeBuffer) {
141                byteCount = (input2.limit() - position) * 4;
142            }
143            result = ByteBuffer.allocate(byteCount).order(input2.order());
144            FloatBuffer result2 = result.asFloatBuffer();
145            for (int i = 0; i < byteCount / 4; i++) {
146                result2.put(input2.get());
147            }
148            input2.position(position);
149        } else if (input instanceof DoubleBuffer) {
150            DoubleBuffer input2 = (DoubleBuffer) input;
151            int position = input2.position();
152            if (convertWholeBuffer) {
153                byteCount = (input2.limit() - position) * 8;
154            }
155            result = ByteBuffer.allocate(byteCount).order(input2.order());
156            DoubleBuffer result2 = result.asDoubleBuffer();
157            for (int i = 0; i < byteCount / 8; i++) {
158                result2.put(input2.get());
159            }
160            input2.position(position);
161        } else if (input instanceof LongBuffer) {
162            LongBuffer input2 = (LongBuffer) input;
163            int position = input2.position();
164            if (convertWholeBuffer) {
165                byteCount = (input2.limit() - position) * 8;
166            }
167            result = ByteBuffer.allocate(byteCount).order(input2.order());
168            LongBuffer result2 = result.asLongBuffer();
169            for (int i = 0; i < byteCount / 8; i++) {
170                result2.put(input2.get());
171            }
172            input2.position(position);
173        } else {
174            throw new RuntimeException("Unimplemented Buffer subclass.");
175        }
176        result.rewind();
177        // The OpenGL API will interpret the result in hardware byte order,
178        // so we better do that as well:
179        result.order(ByteOrder.nativeOrder());
180        return result;
181    }
182
183    public void getArrayElement(int index, double[] result) {
184        if (mTempByteBuffer == null) {
185            throw new IllegalArgumentException("undefined pointer");
186        }
187        if (mStride < 0) {
188            throw new IllegalArgumentException("invalid stride");
189        }
190
191        int stride = getStride();
192        ByteBuffer byteBuffer = mTempByteBuffer;
193        int size = mSize;
194        int type = mType;
195        int sizeofType = sizeof(type);
196        int byteOffset = stride * index;
197
198        for (int i = 0; i < size; i++) {
199            switch (type) {
200            case GL10.GL_BYTE:
201            case GL10.GL_UNSIGNED_BYTE:
202                result[i] = byteBuffer.get(byteOffset);
203                break;
204            case GL10.GL_SHORT:
205                ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
206                result[i] = shortBuffer.get(byteOffset / 2);
207                break;
208            case GL10.GL_FIXED:
209                IntBuffer intBuffer = byteBuffer.asIntBuffer();
210                result[i] = intBuffer.get(byteOffset / 4);
211                break;
212            case GL10.GL_FLOAT:
213                FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
214                result[i] = floatBuffer.get(byteOffset / 4);
215                break;
216            default:
217                throw new UnsupportedOperationException("unknown type");
218            }
219            byteOffset += sizeofType;
220        }
221    }
222}
223